これはJupyter Advent Calendar 2017の11日目の記事です。
この記事では、「Rはそれなりに触ってきたけど、Pythonはまだ学習中で思い通りにコードが書けない」という人1や「Pythonを使わなきゃいけないような状況でも執念でRを使いたい」という人2向けに、「特定の処理のみをPythonに任せて、基本的なデータ処理はRでやる」方法について、簡単に紹介したいと思います。3
なぜRとPythonを共存させたいのか
私は、業務&趣味で、データ分析や可視化をするときにJupyterを利用しています。元々、RStudioを利用していたのですが、最近はPythonを書くことが増えてきた&処理過程や結果を共有しやすいなどの理由から、Jupyterを使うことが多くなってきました。
しかし、元々R(RStudio)を使っていた自分にとっては、以下のような点から微妙に使いにくさを感じていました。
- 一部の処理についてはRの方が早く楽に書ける
- しかし、Rのカーネルを選ぶとPythonのipywidgetsなどが使えない
- 逆もまた然り…
このような使いにくさを解消するために何か良い方法ないかなーと調べていたら、それっぽいやり方を見つけたので、その方法を簡単に紹介したいと思います。
なにをやったのか
元々、Jupyter Notebook内にShinyをねじ込んでインタラクティブなダッシュボードを用意したかったのですが、結構大変そうだったので、方針を変えてPythonとRを一つのノートブック内に共存させて、「Rで前処理などをしつつ、可視化などの部分でのみPythonを書く」という方法で対処することにしました。
実際には、以下のような流れでやりました。
- PythonからRを呼び出すためのパッケージをインストール
- マジックコマンドでRを呼び出してデータ処理、その後Pythonに渡す
- ipywidgetsなどでインタラクティブな可視化
- nbdashboardでそれっぽく見せる
ipywidgetsやnbdashboardに関しては他の方が分かりやすい記事をたくさん書かれているので、今回は1と2の話をしたいと思います。
実行環境
- macOS Sierra
- anaconda3-4.4.0 (Python3.6)
- conda 4.3.30
- Jupyter 4.3.0
という感じです。基本的にanacondaの中にあります。
パッケージのインストール
PythonからRを使うためのrpy2というパッケージがあるので、こちらをインストールします。
基本的にrpy2を入れれば、あとは楽に進みます。rpy2のインストールも楽です。
以下でいけます。
conda install rpy2
ちなみに、↑を実行すると、この辺がインストールされるようです。
The following NEW packages will be INSTALLED:
cairo: 1.14.8-0
fontconfig: 2.12.1-3
gettext: 0.19.8.1-hb0f4f8b_2
glib: 2.50.2-1
gsl: 2.2.1-h002c638_3
harfbuzz: 0.9.39-2
krb5: 1.14.2-hc0fd8ed_4
libedit: 3.1-hb4e282d_0
libffi: 3.2.1-h475c297_4
libssh2: 1.8.0-h1218725_2
ncurses: 6.0-hd04f020_2
pango: 1.40.3-1
pcre: 8.39-1
pixman: 0.34.0-hca0a616_3
r-assertthat: 0.2.0-r342hacfac53_0
r-base: 3.4.2-hc151561_0
r-bh: 1.65.0_1-r342hc3f23d0_0
r-bindr: 0.1-r342hb4d41c9_0
r-bindrcpp: 0.2-r342h94b3c25_0
r-bit: 1.1_12-r342hf8cc2cf_0
r-bit64: 0.9_7-r342h1cba8d6_0
r-blob: 1.1.0-r342h4b1ee69_0
r-dbi: 0.7-r342h6aefa47_0
r-dbplyr: 1.1.0-r342h9881601_0
r-digest: 0.6.12-r342h7ffa501_0
r-dplyr: 0.7.4-r342hd462e57_0
r-glue: 1.1.1-r342hfa53b3f_0
r-magrittr: 1.5-r342hc800aed_4
r-memoise: 1.1.0-r342h0d1069b_0
r-pkgconfig: 2.0.1-r342h037cecb_0
r-plogr: 0.1_1-r342he1be899_0
r-purrr: 0.2.3-r342h7646bf1_0
r-r6: 2.2.2-r342hd083555_0
r-rcpp: 0.12.13-r342hd23d99a_0
r-rlang: 0.1.2-r342h6f7de11_0
r-rsqlite: 2.0-r342h13ed314_0
r-tibble: 1.3.4-r342h9aabc0a_0
rpy2: 2.9.0-py36r342h301bfa9_0
anacondaの下に改めて別のRを入れる感じになるんですかね。
デフォルトで入れているっぽいパッケージに若干物足りなさを感じますが、今回はひとまず気にしないでおきましょう…(tidyverseで入れてくれればいいのに)。
マジックコマンドでRを呼び出してデータ処理
先ほどインストールしたrpy2をJupyterのNotebook上で使えるように、コードセル内にマジックコマンドを記述する必要があります。
こちらも単純で、以下でいけます。
%load_ext rpy2.ipython
ただし、↑を実行すると、_rinterface.cpython-36m-darwin.so requires version 9.0.0 or later, but libiconv.2.dylib provides version 8.0.0
みたいなエラーが返ってきて上手くいかないパターンもあるようです。
そんなときは、以下のような感じでバージョンが合っていないやつをアップデートしてあげれば上手くいくはずです。
conda update libiconv
さて、Rでデータ処理をしてみましょう。
先ほどの%load_ext
で読み込んだら、あとは同一ノートブック内に%R
に続けてRのコードを書けます。雰囲気はこんな感じです。(中身はかなりテキトーに書いてます…)
import pandas as pd
import numpy as np
pydata = pd.DataFrame(np.random.randn(10,3), columns=['a','b','value'])
# ここからR
%load_ext rpy2.ipython
%R require(dplyr)
# 自分でデータフレームを作成したり…
%R data <- data.frame(hoge, fuga, piyo)
%R group_data <- data %>% group_by(piyo) %>% summarise_all(funs(mean))
# Python側で用意したデータをRに渡すこともできたりします(-iでインプット)
%R -i pydata
%R join_data <- data %>% left_join(pydata, by=c("hoge"="a"))
# R側で処理したデータをPythonに渡すときも簡単(-oでアウトプット)
%R -o join_data
例えば、irisをSpeciesごとにグルーピングして平均をとるという処理をしたあと、%R -o data
とすることで、R側で処理をおこなったデータフレームがPython側のオブジェクトとして利用できるようになっていることがわかると思います(%Rが頭にないところは、Pythonのコードになります)。
%R require(dplyr)
%R data <- iris %>% group_by(Species) %>% summarise_all(funs(mean))
%R -o data
data
あとは、%R -o
でPython側に渡したデータでplotなどをしていけば色々できそうな気配がしてきますね。
まとめ
以上、簡単に一つのノートブック内にRとPythonを共存させる方法を紹介させていただきました。
基本的に%load_ext
$R -i
%R -o
の3つを覚えておけば、あとは渡されるデータの型などに合わせて処理をおこなえば、だいたいのことはできると思います。