この文書は,RStudio他によるRパッケージreticulate
(Version 0.7) のビネット"R interface to Python"の翻訳です.
License: Apache License 2.0
概要
reticulate パッケージはPythonのモジュール,クラス,関数へのRインターフェースを提供します.たとえば次のコードでは,Pythonのos
モジュールをインポートして,その中の関数を呼び出しています.
library(reticulate)
os <- import("os")
os$chdir("tests")
os$getcwd()
Pythonのモジュールやクラスの中の関数やその他のデータには,$
演算子によってアクセスできます(Rのリストや環境,参照クラスを操作するやり方と同様です).
Pythonを呼び出すときに,Rのデータ型はPythonの同等な型に自動的に変換されます.PythonからRに値が返されるときには,逆にRの型に変換されます.型は以下のように変換されます.
R | Python | 例 |
---|---|---|
一要素のベクトル | スカラー |
1 , 1L , TRUE , "foo"
|
多要素のベクトル | リスト |
c(1.0, 2.0, 3.0) , c(1L, 2L, 3L)
|
複数の型を含むリスト | タプル | list(1L, TRUE, "foo") |
名前付きリスト | 辞書 |
list(a = 1L, b = 2.0) , dict(x = x_data)
|
行列/配列 | NumPyの配列(ndarray) | matrix(c(1,2,3,4), nrow = 2, ncol = 2) |
関数 | Pythonの関数 | function(x) x + 1 |
NULL, TRUE, FALSE | None, True, False |
NULL , TRUE , FALSE
|
カスタムクラスのPythonオブジェクトが返ってくる場合には,Rからそのオブジェクトへの参照が返されます.このオブジェクトに対しては,まるでRの参照クラスのインスタンスであるかのようにして,メソッドを呼び出したり,プロパティにアクセスしたりできます.
reticulate パッケージは,バージョン2.7以降のすべてのPythonで動作します.オプションとしてNumpyが統合できますが,Numpy 1.6以上が必要です.
インストール
reticulateはCRANから以下のようにしてインストールできます.
install.packages("reticulate")
Pythonの場所の特定
使用したいバージョンのPythonがシステムのPATH
にある場合には,(Sys.which
によって)自動的にそのPythonが見つかり,使用されます
あるいは,以下の関数のどれかを用いて,他のバージョンのPythonを指定することもできます.
関数 | 説明 |
---|---|
use_python | 特定のPythonバイナリへのパスを指定する. |
use_virtualenv | Pythonのvirtualenvを含むディレクトリを指定する. |
use_condaenv | condaの環境を指定する. |
例:
library(reticulate)
use_python("/usr/local/bin/python")
use_virtualenv("~/myenv")
use_condaenv("myenv")
reticulate でNumpyの機能を使うにはNumpy 1.6以上が必要になるので,この要件を満たすバージョンのPythonの方が望ましいです.
また,デフォルトではuse
系関数はPythonがどこで見つかるかのヒントにすぎないということに注意してください(つまり,指定されたバージョンのPythonが存在しなくてもエラーは出ません).指定されたバージョンのPythonが実際に存在することを保証するには,required
引数を追加します.
use_virtualenv("~/myenv", required = TRUE)
Pythonは以下の順序で探索されて見つかった場所にあるバージョンが使用されます.
-
use_python
,use_virtualenv
,use_condaenv
を呼び出して指定した場所 -
RETICULATE_PYTHON
環境変数で指定した場所 -
(
Sys.which
関数によって)システムのPATH
で見つかるPythonの場所 -
その他の慣習的にPythonが配置される場所.
/usr/local/bin/python
,/opt/local/bin/python
等.
典型的な用途では,Rセッションで最初にimport
を呼んだときにPythonの探索とバインディングが実行されます.その結果,import
の呼び出しで指定したモジュールを含むバージョンのPythonが優先的に使用されます(すなわち,指定のモジュールを含まないバージョンのPythonはスキップされます).
py_config
関数を使うと,使用しているバージョンのPythonや,システムで見つかる他のバージョンのPythonに関する情報を問い合わせることができます.
py_config()
モジュールのインポート
import
関数を使って任意のPythonモジュールをインポートすることができます.例を示します.
difflib <- import("difflib")
difflib$ndiff(foo, bar)
filecmp <- import("filecmp")
filecmp$cmp(dir1, dir2)
import_main
関数とimport_builtins
関数によって,デフォルトでコードが実行される場所であるmainモジュールと,組み込みのPython関数群にアクセスすることができます.例を示します.
main <- import_main()
py <- import_builtins()
py$print('foo')
一般的に,ファイルや文字列からPythonコードを実行して,その結果にアクセスしたい場合にmainモジュールが役立ちます(さらなる詳細は以下の節を見てください).
オブジェクトの変換
PythonのオブジェクトがRに返されるとき,デフォルトではRの同等な型に変換されます.ですが,もしPythonからRへの変換を明示的にし,ネイティブなPythonのオブジェクトを扱うのをデフォルトの設定にしたいのであれば,import
関数にconvert=FALSE
を渡せばよいです.
# numpyをインポートし,PythonからRへの自動変換を禁止する
np <- import("numpy", convert = FALSE)
# NumPyで配列を操作する
a <- np$array(c(1:4))
sum <- a$cumsum()
# 最後に明示的にRに変換する
py_to_r(sum)
上で示したように,計算の最後にRのオブジェクトへのアクセスが必要であれば,py_to_r
関数を明示的に呼び出せばよいです.
コードの実行
py_run_file
関数とpy_run_string
関数を使って,mainモジュールの中でPythonコードを実行できます.これらの関数は両方ともPythonのmainモジュールへの参照を返すので,実行結果にアクセスすることができます.例を示します.
py_run_file("script.py")
main <- py_run_string("x = 10")
main$x
リスト,タプル,辞書
Rの型からPythonの型への自動変換は大抵の場合にうまくいきますが,Python側が期待している型を与えるためには,R側でより明示的な操作が必要な場合もあります.
たとえば,PythonのAPIがリストを要求しているのにRの一要素のベクトルを渡すと,これはPythonのスカラーに変換されてしまいます.これを克服するには,たんにRのlist
関数を明示的に使えばよいです.
foo$bar(indexes = list(42L))
同様に,PythonのAPIがリストではなくタプルを要求することがあるかもしれませんが,その場合にはtuple
関数が使えます.
tuple("a", "b", "c")
Rの名前付きリストはPythonの辞書に変換されますが.dict
関数を使って明示的にPythonの辞書を作成することもできます.
dict(foo = "bar", index = 42L)
これは,(文字列ではない)より複雑なオブジェクトをキーに持つ辞書を渡す必要がある場合に有用かもしれません.
コンテキスト
Rのwith
総称関数を使って,Pythonのコンテキストマネージャオブジェクトを操作できます(Pythonではwith
キーワードを使って同じことができます).例を示します.
py <- import_builtins()
with(py$open("output.txt", "w") %as% file, {
file$write("Hello, there!")
})
この例では,ファイルを開いて,そのファイルがwithブロックの最後に自動的に閉じられることを保証しています.%as%
演算子を使って,コンテキストマネージャが作成したオブジェクトに別名を与えていることに注目してください.
イテレータ
もしPythonのAPIがイテレータやジェネレータを返す場合には,iterate
関数を使ってこれを操作することができます.iterate
関数を使うと,イテレータが返す各要素に対してRの関数を適用できます.
iterate(iter, print)
iterate
に関数を渡さないと,結果が集められてRのベクトルになります.
results <- iterate(iter)
iterate
関数によってイテレータの値は消費されてしまうことに注意してください.
a <- iterate(iter) # 結果は空でない
b <- iterate(iter) # 要素はすでに消費されてしまったので,結果は空になる
呼び出し可能オブジェクト
Pythonのオブジェクトの中には,メソッドやプロパティへのアクセスだけでなく,呼び出し可能な(つまり普通の関数のように引数を与えて呼び出すことができる)ものがあります.呼び出し可能なPythonオブジェクトは,関数ではなくオブジェクトとしてRに返ってくるものの,$call()
メソッドによって呼び出し可能な関数を実行できます.例を示します.
# 呼び出し可能オブジェクトを取得
parser <- spacy$English()
# オブジェクトを関数として呼び出す
parser$call(spacy)
高度な関数
主にPythonライブラリに対して高水準のRインターフェースを作成するときに役立つ,より高度な関数も利用可能です.
Pythonオブジェクト
RからPythonのオブジェクトを操作するには,通常は$
演算子を使って必要なオブジェクトの機能にアクセスします.$
を使うと,Pythonのオブジェクトは可能であれば自動的にRの同等なオブジェクトに変換されますが,以下の関数を用いればPythonのオブジェクトをより低水準で操作できます(たとえば,明示的にpy_to_r
を呼ばない限りRのオブジェクトへの変換は行われません).
関数 | 説明 |
---|---|
py_has_attr | オブジェクトが指定した属性を持つか確認する. |
py_get_attr | Pythonオブジェクトの属性を取得する. |
py_set_attr | Pythonオブジェクトの属性を設定する. |
py_list_attributes | Pythonオブジェクトの全属性の一覧を取得する. |
py_call | 指定した引数でPythonの呼び出し可能オブジェクトを呼び出す. |
py_to_r | PythonオブジェクトをRの同等なオブジェクトに変換する. |
r_to_py | RのオブジェクトをPythonの同等なオブジェクトに変換する. |
設定
以下の関数を用いると,現在のシステムで利用可能なPythonの設定に関する情報を問い合わせることができます.
関数 | 説明 |
---|---|
py_available | Pythonへのインターフェースがこのシステムで利用可能か確認する. |
py_numpy_available | NumPyへのRインターフェースが利用可能か確認する(要NumPy 1.6以上). |
py_module_available | Pythonのモジュールがこのシステムで利用可能か確認する. |
py_config | 使用中のPythonの場所とバージョンの情報を取得する. |
出力の制御
以下の関数を用いるとPythonからの出力を捕捉したり抑制したりできます.
関数 | 説明 |
---|---|
py_capture_output | 指定した式に対するPythonの出力を捕捉してRの文字ベクトルとして返す. |
py_suppress_warnings | 指定した式を実行するが,Pythonの警告の表示は抑制する. |
その他
以下の関数は,その他の様々な低水準の機能を提供します.
関数 | 説明 |
---|---|
py_unicode | 文字列をPythonのユニコードオブジェクトに変換する. |
py_str | Pythonオブジェクトの文字列表現を取得する. |
py_is_null_xptr | Pythonオブジェクトがnullなexternalptrであるか確認する. |
py_validate_xptr | Pythonオブジェクトがnullなexternalptrであるか確認し,そうであればエラーを投げる. |
パッケージでの使用
CRANでチェックとテスト
reticulateを他のRパッケージで使うのであれば,次のことを考慮する必要があります.それは,パッケージがCRANに提出される際に,CRANのテスト用サーバにはPythonもNumPyも,あなたがパッケージでラップしようとしている他のPythonモジュールも存在しないかもしれないということです.
あなたのパッケージがCRANでうまく動作することを保証するには,以下の2つのことをやってておくべきです.
-
パッケージの中で使うPythonモジュールをインポートする際には,モジュール(とPython)がそれらを最初に使うときにだけロードされることを保証するために,
delay_load
オプションを使うべきです.# 自分のパッケージで使用したいpythonの'foo'モジュール foo <- NULL .onLoad <- function(libname, pkgname) { # fooモジュールを遅延ロードする($でアクセスするときにのみロードされる) foo <<- import("foo", delay_load = TRUE) }
-
テストを書く際には,モジュールが利用可能かどうか確認し,利用不可能であればテストをスキップするようにします.たとえばtestthatパッケージを使っているのであれば,以下のようになるでしょう.
# 'foo'モジュールがなければテストをスキップするためのヘルパ関数 skip_if_no_foo <- function() { have_foo <- py_module_available("foo") if (!have_foo) skip("テストにfooが利用できません!") } # このヘルパ関数をすべてのテストで呼ぶようにする test_that("期待通りに動く", { skip_if_no_foo() # ここにテストコードを書く })
S3メソッド
reticulate によってR側に露出しているPythonオブジェクトのクラスはRにも持ち越されるので,クラスに対してS3メソッドを書いて,たとえばstr
やprint
の動作をカスタマイズすることができます(ただし通常はそうする必要はありません.デフォルトのstr
メソッドやprint
メソッドはPyObject_Str
を呼び出しますが,これが普通は許容可能なデフォルトの動作を提供するからです.
もし本当にPythonのクラス向けにカスタマイズしたS3メソッドを実装すると決めたのであれば,次のことに留意するのが大切です.すなわち,Rセッションの終了時にはPythonオブジェクトへのコネクションが失われるので,あるRセッションで保存した.RDataを後続のRセッションでリストアすると,Pythonオブジェクトが実質的に失われてしまうということです(正確に言うと,RのNULL
なexternalptr
オブジェクトになってしまいます).
これが意味するところは,S3メソッドでPythonオブジェクトを操作する前には,常にpy_is_null_xptr
を使うべきだということです.例を示します.
#' @export
summary.MyPythonClass <- function(object, ...) {
if (py_is_null_xptr(object))
stop("Object is NULL")
else
# オブジェクトを操作してサマリを生成する
}
これをより簡単に行うために,いくつかショートカット用メソッドが用意されています.py_validate_xptr
関数は必要な確認を行い,失敗したら自動的にエラーを投げます.したがって上の例は次のように書き直すことができるでしょう.
#' @export
summary.MyPythonClass <- function(object, ...) {
py_validate_xptr(object)
# オブジェクトを操作してサマリを生成する
}
最後になりますが,reticulateパッケージはpy_str
総称関数をエクスポートしており,そのメソッドはstr
メソッドから適切な検証(オブジェクトがNULLなら<pointer: 0x0>
を返す)を経た後にのみ呼び出されます1.以下のようにしてpy_str
のメソッドを実装できます.
#' @importFrom reticulate py_str
#' @export
py_str.MyPythonClass <- function(object, ...) {
# オブジェクトを操作して文字列を生成する
}
要するに,カスタムのstr
メソッドやprint
メソッドを提供するにはpy_str
を実装してください.その他のS3メソッドについては,オブジェクトを操作する前に必ずpy_validate_xptr
やpy_is_null_xptr
を呼ぶようにしてください.
-
[訳注]若干わかりにくいように思うので補足する.まずreticulateによって,任意のPythonオブジェクトはR側では
python.builtin.object
クラスを継承したオブジェクトとして見える.python.builtin.object
に対してはstr
メソッドが定義されており,このメソッドがpy_str
総称関数を呼び出す.そしてpy_str
総称関数は引数のチェックをした後にメソッドを呼ぶという構造になっている.reticulate:::str.python.builtin.object
## function (object, ...) ## { ## cat(py_str(object), "\n", sep = "") ## } ## <environment: namespace:reticulate>
reticulate::py_str
↩## function (object, ...) ## { ## if (!inherits(object, "python.builtin.object")) ## py_str.default(object) ## else if (py_is_null_xptr(object) || !py_available()) ## "<pointer: 0x0>" ## else UseMethod("py_str") ## } ## <environment: namespace:reticulate>