Jupyter 运行 可以从 Python 笔记本中分离出一个单独的 R 笔记本吗?

Can Jupyter run a separate R notebook from within a Python notebook?

我有一个 Jupyter 笔记本 (python3),它是一个批处理作业 -- 它 运行 是三个独立的 python3 笔记本,使用 %run。我想从我的批次中调用第四个 Jupyter R-kernel notebook。

有没有办法从 Jupyter 中的 Python notebook 执行外部 R notebook / iPython?

当前设置:

run_all.ipynb: (python3 内核)

%run '1_py3.ipynb'
%run '2_py3.ipynb'
%run '3_py3.ipynb'
%run '4_R.ipynb'

三个 python3 笔记本 运行 正确。 R notebook 运行 在 Jupyter 中单独打开时正确 - 但是当使用 %runrun_all.ipynb 调用时失败。解释为python,单元格第一行给出python错误:

cacheDir <- "caches"

TypeError: bad operand type for unary -: 'str'

我对 运行从 python 笔记本中创建一个单独的 R 笔记本的任何解决方案感兴趣——Jupyter magic、shell、python 库等.我也会对解决方法感兴趣 - 例如一种方法(如 shell 脚本)将 运行 所有四个笔记本(python3 和 R),即使这不能从 python3 笔记本内部完成。

(注意:我已经了解如何在单元格中嵌入 %%R。这不是我想要做的。我想调用一个完整的独立 R 笔记本。)

我不认为你可以使用 %run 魔法命令,因为它在当前内核中执行文件。

Nbconvert 有一个执行 API 允许您执行笔记本。所以你可以创建一个 shell 脚本来执行你所有的笔记本,如下所示:

#!/bin/bash
jupyter nbconvert --to notebook --execute 1_py3.ipynb
jupyter nbconvert --to notebook --execute 2_py3.ipynb
jupyter nbconvert --to notebook --execute 3_py3.ipynb
jupyter nbconvert --to notebook --execute 4_R.ipynb

由于您的笔记本不需要共享状态,因此应该没问题。或者,如果你真的想在笔记本上做,你可以使用 execute Python API 从你的笔记本调用 nbconvert。

import nbformat
from nbconvert.preprocessors import ExecutePreprocessor

with open("1_py3.ipynb") as f1, open("2_py3.ipynb") as f2, open("3_py3.ipynb") as f3, open("4_R.ipynb") as f4:
    nb1 = nbformat.read(f1, as_version=4)
    nb2 = nbformat.read(f2, as_version=4)
    nb3 = nbformat.read(f3, as_version=4)
    nb4 = nbformat.read(f4, as_version=4)

ep_python = ExecutePreprocessor(timeout=600, kernel_name='python3')
#Use jupyter kernelspec list to find out what the kernel is called on your system
ep_R = ExecutePreprocessor(timeout=600, kernel_name='ir')

# path specifies which folder to execute the notebooks in, so set it to the one that you need so your file path references are correct
ep_python.preprocess(nb1, {'metadata': {'path': 'notebooks/'}})
ep_python.preprocess(nb2, {'metadata': {'path': 'notebooks/'}})
ep_python.preprocess(nb3, {'metadata': {'path': 'notebooks/'}})
ep_R.preprocess(nb4, {'metadata': {'path': 'notebooks/'}})

with open("1_py3.ipynb", "wt") as f1, open("2_py3.ipynb", "wt") as f2, open("3_py3.ipynb", "wt") as f3, open("4_R.ipynb", "wt") as f4:
    nbformat.write(nb1, f1)
    nbformat.write(nb2, f2)
    nbformat.write(nb3, f3)
    nbformat.write(nb4, f4)

请注意,这几乎只是从 nbconvert execute API 文档复制的示例:link

我能够使用 从 python3 笔记本实现 运行 R 笔记本的两个解决方案。

1。从 ! shell 命令

调用 nbconvert

向 python3 笔记本添加一个简单的 ! shell 命令:

!jupyter nbconvert --to notebook --execute r.ipynb

所以笔记本看起来像这样:

  1. %run '1_py3.ipynb'
  2. %run '2_py3.ipynb'
  3. %run '3_py3.ipynb'
  4. !jupyter nbconvert --to notebook --execute 4_R.ipynb

这个看起来简单好用

2。在单元格中调用 nbformat

将此添加到批处理笔记本的单元格中:

import nbformat
from nbconvert.preprocessors import ExecutePreprocessor

rnotebook = "r.ipynb"
rnotebook_out = "r_out.ipynb"
rnotebook_path = '/home/jovyan/work/'

with open(rnotebook) as f1:
    nb1 = nbformat.read(f1, as_version=4)

ep_R = ExecutePreprocessor(timeout=600, kernel_name='ir')
ep_R.preprocess(nb1, {'metadata': {'path': rnotebook_path}})

with open(rnotebook_out, "wt") as f1:
    nbformat.write(nb1, f1)

这是基于 Louise Davies 的回答(基于 nbcovert 文档示例),但它只处理一个文件——非 R 文件可以在单独的单元格中处理 %run .

如果批处理笔记本与其正在执行的笔记本位于同一文件夹中,则可以使用 %pwd shell 魔法设置路径变量,其中 returns批处理笔记本。

当我们使用 nbformat.write 时,我们在替换原始笔记本(方便直观,但可能损坏或破坏文件)和创建新文件以供输出之间进行选择。如果不需要单元格输出(例如在操作文件和写入日志的工作流程中),第三个选项是完全忽略写入单元格输出。

缺点

这两种方法的一个缺点是它们不会将单元格结果通过管道传输回主笔记本显示——这与 %run 在其结果单元格中显示笔记本输出的方式相反。 !jupyter nbconvert 方法似乎显示了来自 nbconvert 的标准输出,而 import nbconvert 方法什么也没显示。