5

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

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

当前设置:

run_all.ipynb: (python3 内核)

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

三个 python3 笔记本运行正常。R 笔记本在 Jupyter 中单独打开时可以正常运行 - 但是在使用%runfrom调用时会失败run_all.ipynb。它被解释为python,并且单元格在第一行给出了python错误:

cacheDir <- "caches"

TypeError:一元操作数类型错误-:'str'

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

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

4

2 回答 2

6

我认为您不能以%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

由于您的笔记本不需要共享状态,这应该没问题。或者,如果您真的想在笔记本中执行此操作,您可以使用执行 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 执行 API 文档复制的示例: 链接

于 2017-11-01T10:42:29.130 回答
4

我能够使用答案来实现从 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 docs 示例),但它只处理一个文件——非 R 文件可以在单独的单元格中处理%run

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

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

缺点

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

于 2017-11-01T20:25:37.803 回答