使用rpy2包,通过python作粘合剂,使用R的计算功能,其中常用的一步是在python中作好某个数据的预处理之后传给R作进一步处理。基本数据结构好处理,麻烦的是集合型的数据结构,因为两者的数据格式定义不太一样,比如python常用的集合型数据结构是tuple, list, dict,而R是vector, list, array, data.frame等。所以在rpy2.robjects包下准备了一些转换对象,如RVector, RArray, RDataFrame等等。实际上大多数R调用的返回都是用这些对象表示的。
给R进程传递一个RVector对象比较简单,构造一个RVector对象,构造时传递一个list就完了。比较麻烦的是在python里生成data.frame数据结构,方法有两种,一是利用RDataFrame的构造函数,在python中直接生成,但需要给它传递一rinterface.SexpVector对象,这是一个rpy2的底层对象,我嫌麻烦没管它;另一种方法是在内嵌的R进程中生成,然后返回给python。示例代码如下:
>>> d = {'value': robjects.IntVector((1,2,3)), 'letter': robjects.StrVector(('x', 'y', 'z'))} >>> dataf = robjects.r['data.frame'](**d) >>> print(dataf.colnames()) [1] "letter" "value"
注意这样方式转换过去的data.frame列序跟你在python里的排序可能是不一样的,这是因为python的dict的key本来就是无序的,如果忽略这点,有可能在R代码里引入BUG,一种避免的方式是在R代码里尽量使用D$name这种键值形式来获取数据,而非D[[1]]这种下标形式。
Things are hopefully falling into place with the coming release.
Creating an R data.frame can be done using the constructor for the Python
class DataFrame orr using the R function data.frame:
from rpy2.robjects.packages import importr
from rpy2.robjects import globalenv
base = importr("base")
# order of columns not preserved
dataf = base.data_frame(foo = base.c(1,2,3), bar = base.c('a', 'b', 'c'))
# order of columns preserved
dataf = base.data_frame.rcall((('foo', base.c(1,2,3)),('bar', base.c('a', 'b', 'c'))), globalenv)
That sounds great! It seems more beautiful in that style. It will be better if the R data.frame could be done by DataFrame constructor, just as easy as IntVector.