やりたいこと
RMarkdownは下記のようにすることで、pythonを呼び出して使うことが出来るが、これはチャンク毎に1個のセッションを呼び出しているので、結果は保存されない。
このようにするとRmarkdownでpythonを使うことができる
```{python}
import sys
ver = sys.version
print(ver)
```
2.7.13 (default, Jan 19 2017, 14:48:08)
[GCC 6.3.0 20170118]
ただし、チャンクの内容をファイルにして`python <チャンクの内容>`としているだけのようなので、
```{python}
import sys
import subprocess
print(sys.executable, sys.argv)
```
('/usr/bin/python', ['/tmp/Rtmp2hwE4t/chunk-code-56da38833dcb.txt'])
チャンクをまたがった記述などはできない
```{python}
print(ver) # 最初のチャンクで定義したver ➔ 無い
```
Traceback (most recent call last):
File "/tmp/RtmpCqNMJ1/chunk-code-76ef3b9243de.txt", line 1, in <module>
print(ver)
NameError: name 'ver' is not defined
Jupyter(IPython Kernel)のセッションは別に上げておき、これに接続して使うようにすることで、チャンクを乗り越えた処理が可能なのではないかと考えた。
追記:2017/11/28
コメントで追加情報ちょっとあります。
チャンクを乗り越えた処理をする、というのは、RStudio/reticulateを使うコトで出来る(更に、
pyとRの間をまたがった処理まで出来る)ようで、時期アップデートではそれがデフォルトになるのだとか。
使い方等、詳しくは@yutannihilationさんのコメントを参照
やったこと
下記のようなスクリプトを作成しておき
#!/bin/bash -f
# 下記2行はpyenv 上にあるのでこうしているが
# 普通にパスが通っているなら不要
source /etc/profile.d/pyenv.sh
pyenv shell anaconda3-5.0.1
SESSION_FILE_NAME=${HOME}/session.json
if [ -f $SESSION_FILE_NAME ]; then
# session found
jupyter run --existing $SESSION_FILE_NAME $1
else
# session start
python -m ipykernel_launcher -f $SESSION_FILE_NAME > /dev/null &
# waiting for ipykernel start...
while [ ! -f $SESSION_FILE_NAME ]; do
sleep 0.2
done
# then, run
jupyter run --existing $SESSION_FILE_NAME $1
fi
この用にオプションを設定しておくことで、
```{r setup, echo=FALSE}
# どうも、setup、という名前のチャンクじゃないと駄目っぽい・・?
library(knitr)
opts_chunk$set(engine.path = '/path/to/jupyter_wrap.sh')
```
こんな感じで、チャンクをまたいで処理してくれるはず。
```{python}
import sys
ver = sys.version
print(ver)
```
3.6.3 |Anaconda, Inc.| (default, Oct 13 2017, 12:02:49)
[GCC 7.2.0]
```{python}
print(ver) # 最初のチャンクで定義したver ➔ ある!
```
3.6.3 |Anaconda, Inc.| (default, Oct 13 2017, 12:02:49)
[GCC 7.2.0]
これってつまりJupyter notebookもipython_kernelのクライアントの一つに過ぎず、似たようなことをRMarkdownでやっている感じなんじゃないかな。
おそらくpython以外のkernelでも出来るのではないかという気がする。
また、残念ながら、標準入出力を介したやり取りしかできないが、RStudio/reticulateを使うことで、pythonのオブジェクトや、図などもやり取り出来るかもしれない。
参考:https://stackoverflow.com/questions/36437028/rstudio-with-python-matplotlib-graph
Pandas DataFrameと、RのDataFrameの間はArrowとかFeatherとかでできそう。
なんでわざわざRMarkdownを?と思うかもしれないが、gitとの相性とかを考えるとRMarkdownいいなーでも、pythonのほうが情報多いし、出来ることも違いそうだなーと思って色々と調べていたのでした。
tidyverseとpipeRは面白いです、ワンライナー好きにはたまらない・・・。
補足1
最初に調べたのは、Jupyterのセッションに接続する方法。
調べたところ、Jupyterのセッションに接続するとはこのような感じである。
$ jupyter console # notebook ではなく、consoleで起動
として
jupyter console
Jupyter console 5.2.0
Python 3.6.3 |Anaconda, Inc.| (default, Oct 13 2017, 12:02:49)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.1.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: %connect_info
{
"shell_port": 33095,
"iopub_port": 56161,
"stdin_port": 60865,
"control_port": 41975,
"hb_port": 45665,
"ip": "127.0.0.1",
"key": "7cec19ae-ae48a07596105f9c998f369e",
"transport": "tcp",
"signature_scheme": "hmac-sha256",
"kernel_name": ""
}
Paste the above JSON into a file, and connect with:
$> jupyter <app> --existing <file>
or, if you are local, you can connect with just:
$> jupyter <app> --existing kernel-12421.json
or even just:
$> jupyter <app> --existing
if this is the most recent Jupyter kernel you have started.
In [2]: a=10
メッセージにある通り、別のシェルなどから
$ jupyter console --existing
とすると、別のipython consoleが立ち上がり、先程のセッションで定義したaを見ることが出来る。
Jupyter console 5.2.0
Python 3.6.3 |Anaconda, Inc.| (default, Oct 13 2017, 12:02:49)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.1.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: a
Out[2]: 10
consoleではなくて、スクリプトファイルを渡したりして実施したい場合は
$ jupyter run --existing - <ファイル名>
とすることでできた。
補足2
ここまで調べて、実際にやったことと同じように、pythonの実行パスとオプションで対処しようとした所、幾つか上手く行かないことがあった。
–existingの後を空(-)にして渡すのが何故かうまくいかない
➔ 明示的にセッションファイルを作成する(run -f オプション)を使うことに
Jupyterの起動もついでにやっちゃろうと、jupyter_wrap.shのような物を作ったのだが、色々試して見たところどうしてもjupyter runが親プロセスと一緒に死んでしまう(親プロセスがなくなったことを検出して自動的にシャットダウンしたかのようなメッセージが出る)ので、ipython_kernelを直接立ち上げたところ、上手く行った。
なお、ipython_kenelを終了するには、RMarkdownで
```{python}
quit()
```
とするか、シェルからjupyter consoleなどで接続して、
In [1]: quit
とする。
Rのセッションをリスタートしたときとかに、一緒に消えてくれたりはしない。