用 papermill 参数化和自动化 Jupyter
你是否曾经创建过 Jupyter notebook
并希望可以使用一组不同的参数生成notebook
?这样做的话你可能至少执行了以下操作之一:
•编辑单元格中的变量并重新运行notebook
,根据需要保存副本。•保存了notebook
的副本,并且可能修改了代码以直接在 .ipynb
文件中编辑值并重新运行notebooks
•构建了一些自定义代码以使用从数据库或配置文件加载的数据设置变量,然后重新运行notebook
这个问题有一个很好的解决方案,可以将交互式笔记本参数化并与自动化作业很好地共存,这就是所谓的papermill
。
动机
许多notebook
用户使用在其notebook
顶部附近指定一个单元格作为全局变量的标准做法。然后修改单元格中的值并运行整个notebook
以获得不同的结果。为了保持输出,作者将手动下载另一种格式的notebook
或将其另存为不同的notebook
文件。但是仅使用notebook
服务器和这些手动方法很快就会变得混乱且难以跟踪,更不用说容易出错了。你编辑的是哪个notebook
? Papermill
有助于解决这个问题。在这篇文章中,我将介绍 papermill
和基本用法,通过一个参数化的例子,最后谈谈使用 cron
完全调度和自动化 notebook
执行的方法。
对于papermill
,notebook
中的一个特殊单元格被指定为参数。当 papermill
通过命令行界面 (CLI) 或使用 Python API 执行参数化notebook
时,参数会传入并在后续单元中执行。这允许notebook
以不同的参数快速运行多次。然后可以将生成的执行后的notebook
保存在各种位置,包括本地或云存储。
安装
要安装 papermill
,请使用 pip
。我建议使用 virtualenv
或 conda
的虚拟环境。我经常推荐使用 pyenv
来安装最新的 Python 版本并创建一个 virtualenv
虚拟环境。
pip install papermill
如果您想使用各种输入和输出选项,如 Amazon 的 s3 或 Microsoft 的 azure,您可以安装所有依赖项。我不会在这里详细介绍,但文档涵盖了这些选项,你甚至可以扩展 papermill
为notebooks
的输入/输出 (I/O) 添加其他处理程序。
pip install papermill[all]
基本使用
大多数用户想要用 papermill
做的第一件事就是参数化notebook
。一旦您运行了 Jupyter
并打开了一个notebook
,您需要做的就是将参数标签添加到包含参数的单元格中。
保存notebook
,现在您可以使用 papermill
执行它了。对于示例notebook
,请使用 CLI 运行notebook
,并提供您自己的名称。
papermill -p name Matt papermill_example1.ipynb papermill_matt.ipynb
此命令告诉 papermill
执行输入 notebook papermill_example1.ipynb
并将输出写入 papermill_matt.ipynb
,同时将参数名称设置为值 Matt
。如果您打开生成的notebook
,将在带有注入参数标签的参数标记之后包含一个新单元格,如下所示。
您现在应该看到如何根据需要添加尽可能多的参数,以便从现有notebook
制作新notebook
。将主notebook
(在我们的例子中是papermill_example1.ipynb
)想象成一个模板,您可以使用它通过快速注入参数来制作任意数量的副本。
API 的基本使用
您可能希望使用 Python 代码获取或构建您注入的参数,因此还可以使用 Python API 来执行 papermill
。我们可以在 Python 脚本中实现与上述完全相同的结果(或在notebook
中,它在那里也能很好地工作 - 并且会动态地向您显示进度)。
import papermill as pm
name = "Matt"
res = pm.execute_notebook(
'papermill_example1.ipynb',
'papermill_{name}.ipynb',
parameters = dict(name=name)
)
{"version_major":2,"version_minor":0,"model_id":"cf8280b216094bf6a75a9536b6505051"}
更多参数传递
到目前为止,我们只传递了一个参数,并使用了 -p
选项来实现这一点。您可以通过几种方式传递参数。
命令行
您可以使用示例notebook
运行所有这些内容,然后自己查看结果。首先,您可以从 CLI
指定多个参数。即使notebook
中尚不存在参数,也可以传入和创建参数。在这种情况下,papermill
将创建一个注入参数单元并在notebook
顶部执行它。
这是一个例子。
papermill -p name Matt -p level 5 -p factor 0.33 -p alive True papermill_example1.ipynb papermill_matt.ipynb
或者用长选项代替......
papermill --parameters name Matt --parameters level 5 --parameters factor 0.33 --parameters alive True papermill_example1.ipynb papermill_matt.ipynb
请注意, -p
或 --parameters
选项将尝试解析整数和浮点数,因此如果您希望将它们解释为字符串,请使用 -r
或 --raw
选项以字符串形式获取所有值。
papermill -r name Matt -r level 5 -r factor 0.33 -r alive True papermill_example1.ipynb papermill_matt.ipynb
您还可以使用 yaml
来指定参数。这可以通过文件(-f
或 --parameters_file
)、字符串(-y
或 --parameters_yaml
)或 base64 编码字符串(-b
或 --parameters_base64
)传入。这允许您传入更复杂的数据,包括列表和字典。
papermill papermill_example1.ipynb papermill_matt.ipynb -y "
name: Matt
level: 5
factor: 0.33
alive: True
sizes:
- 1.0
- 2.5
- 3.7
params:
x: 3
y: 4"
您可以很容易地对字符串进行 base64 编码。(在 Mac 或 Linux 或 Windows WSL 上notebook
文件所在目录中的 shell 中运行此命令)。
echo "
name: Matt
level: 5
factor: 0.33
alive: True
sizes:
- 1.0
- 2.5
- 3.7
params:
x: 3
y: 4" > params.yaml
现在您可以运行文件版本。
papermill papermill_example1.ipynb papermill_matt.ipynb -f params.yaml
或者base64版本
PARAMS=$(cat params.yaml| base64) # makes the base64 version of the yaml file
papermill papermill_example1.ipynb papermill_matt.ipynb -b $PARAMS
无论哪种方式,你都应该了解可以从命令行和 API 将复杂数据传递到notebook
中。这些示例都使用本地文件系统进行notebook
的输入和输出,但也可以从 Amazon s3、Azure、Google Cloud Storage 或 Web 服务器读取和写入notebook
。
检查notebook
可以从 CLI
检查notebook
的可用参数。
$ papermill --help-notebook papermill_example1.ipynb
Usage: papermill [OPTIONS] NOTEBOOK_PATH [OUTPUT_PATH]
Parameters inferred for notebook 'papermill_example1.ipynb':
name: Unknown type (default "Joe")
或者使用 Python API。
pm.inspect_notebook('papermill_example1.ipynb')
{'name': {'name': 'name',
'inferred_type_name': 'None',
'default': '"Joe"',
'help': ''}}
执行完整的工作流程
papermill
的典型工作流程是拥有一个参数化notebook
,使用多个值运行它,然后将生成的notebook
转换为另一种格式以供审查或报告。让我们通过一个示例来了解如何设置。
首先,我们有一个使用 Yahoo! 金融 API 来获取股票价格并绘制股票历史最高价的数据(或者至少是过去两年的最高价,因为我此时只获取那么多数据)。
如果要运行此示例,则需要确保已安装 yfinance API 和 matplotlib。如果需要,您可以使用 pip 安装两者。
我们可以使用papermill
CLI 来检查参数。
$ papermill --help-notebook papermill_example2.ipynb
Usage: papermill [OPTIONS] NOTEBOOK_PATH [OUTPUT_PATH]
Parameters inferred for notebook 'papermill_example2.ipynb':
symbol: Unknown type (default 'AAPL')
我们将用几个符号运行这个notebook
。我选择为此使用 shell 脚本,以便我可以通过计划的 cron
程序运行它。如果需要,这可以使用简单的 Python 脚本轻松完成。但是,如果您使用的是虚拟环境,您最终可能需要一个脚本来确保正确加载 virtualenv
。在这种情况下,在整个过程中使用 shell 脚本可能会更容易。
我还将使用 jupyter nbconvert(或者您可以将其作为 jupyter-nbconvert
运行)命令将notebook
转换为 html 文件,以便通过 Web 浏览器查看。就像 papermill
一样,nbconvert
可通过命令行或使用 Python API 获得。
自动化脚本
#!/bin/bash
set -eux
# activate our virtualenv (this was created using pyenv-virtualenv, yours will be elsewhere)
source /Users/mcw/.pyenv/versions/3.8.6/envs/pandas/bin/activate
# get to the script directory if running via cron
cd $(dirname "${BASH_SOURCE[0]}")
for S in AAPL MSFT GOOG FB
do
papermill -p symbol $S papermill_example2.ipynb papermill_${S}.ipynb
jupyter-nbconvert --no-input --to html papermill_${S}.ipynb
done
您可以从 shell 运行此命令(在调整激活虚拟环境的行之后)。您还可以很容易地安排它在 cron
中定期运行。例如,您可以像下面这样(使用您自己的路径)在每个工作日的下午 4 点运行此报告。
00 16 * * mon-fri /Users/mcw/projects/python_blogposts/tools/run_papermill.sh
扩展示例
只需多一点创意(和 nbconvert
上的软件配置),您就可以将notebooks
输出为 PDF 或其他格式,通过电子邮件发送,或将它们上传到服务器,以便每天更新报告。
请注意,每个符号的notebooks
都保存到本地磁盘。如果需要调试或进一步工作,它们可以在 Jupyter 服务器中打开并轻松重新执行。请注意,如果您正在运行一个自动化作业,那么每次运行时都会更换notebook
。理想情况下,在主模板notebook
上工作,然后通过自动化为每个符号生成新版本。
另一个技巧是papermill
可以读写标准输入和输出。这意味着如果您有其他工具将notebook
文件作为输入,则不必将文件写入磁盘。例如,在上面的 shell 脚本中,我们可以防止为每个符号写出每个单独的notebook
文件,而是在循环中执行以下操作。
papermill -p symbol $S papermill_example2.ipynb | jupyter-nbconvert --stdin --no-input --to html --output report_${S}.html
请注意,如果您这样做,则需要打开主notebook
(papermill_example2.ipynb) 并编辑参数以调试问题。但是,如果您需要节省磁盘空间并且不需要单独调试每个notebook
的能力,那么这可能更可取。
总结
Papermill
是一个用于参数化和执行 Jupyter notebook的库。您可以使用它来自动执行您的notebook
,其中包含您可以想到的任何参数集。接着使用 nbconvert
转换notebook
,以提供可读且有用的notebook
版本。
notebook
自动化还有很多事情要做,但是从 Papermill
开始作为执行和参数化notebook
的工具是一个很好的构建平台。
点击下方阅读原文加入社区会员