rpy2:将data.frame转换为numpy数组

7
我在R中有一个数据框,其中包含许多(125个)阵列的基因表达水平等大量数据。我想使用Python处理数据,主要是因为我对R不熟悉,而且这应该是一个30分钟的工作。
我希望以下代码能够正常工作。为了理解此代码,请注意变量path包含我的数据集的完整路径,加载后会给我一个名为immgen的变量。请注意,immgen是一个对象(Bioconductor ExpressionSet对象),而exprs(immgen)返回一个具有125列(实验)和数万行(命名基因)的数据框。(如果不清楚,这是使用robjects.r调用R代码的Python代码)
import numpy as np
import rpy2.robjects as robjects
# ... some code to build path
robjects.r("load('%s')"%path) # loads immgen
e = robjects.r['data.frame']("exprs(immgen)")
expression_data = np.array(e)

这段代码可以运行,但是expression_data只是一个简单的array([[1]])

我相信e不代表由exprs()生成的数据帧,因为有以下原因:

In [40]: e._get_ncol()
Out[40]: 1

In [41]: e._get_nrow()
Out[41]: 1

但是谁知道呢?即使e代表我的数据框,它不能直接转换为数组也是可以理解的 - 数据框比数组更复杂(有行名和列名),所以也许生活不应该这么简单。然而我仍然无法弄清如何执行转换。文档对我来说有点太简略了,虽然我对文档中的标题的有限理解暗示着这应该是可能的。

有人有想法吗?

2个回答

7
这是我发现的将数据框从R传输到Python最直接可靠的方法。
首先,我认为通过R绑定交换数据是一个不必要的复杂化。R提供了一种简单的导出数据的方法,同样,NumPy有很好的数据导入方法。这里唯一需要的共同接口是文件格式。
data(iris)
iris$Species = unclass(iris$Species)

write.table(iris, file="/path/to/my/file/np_iris.txt", row.names=F, sep=",")

# now start a python session
import numpy as NP

fpath = "/path/to/my/file/np_iris.txt"

A = NP.loadtxt(fpath, comments="#", delimiter=",", skiprows=1)

# print(type(A))
# returns: <type 'numpy.ndarray'>

print(A.shape)
# returns: (150, 5)

print(A[1:5,])
# returns: 
 [[ 4.9  3.   1.4  0.2  1. ]
  [ 4.7  3.2  1.3  0.2  1. ]
  [ 4.6  3.1  1.5  0.2  1. ]
  [ 5.   3.6  1.4  0.2  1. ]]

根据文档(以及我的经验),loadtxt是传统数据导入的首选方法。您还可以向loadtxt传递一个数据类型元组(参数为dtypes),元组中的每个项目对应一列。请注意,“skiprows=1”是用于跳过列标题的(对于loadtxt,行从1开始索引,列从0开始索引)。最后,我在导出之前将数据框因子转换为整数(实际上是因子的基础数据类型)--“unclass”可能是最简单的方法。如果您有大量数据(即不想将整个数据文件加载到内存中但仍需要访问它),则 NumPy的内存映射数据结构(“memmap”)是一个不错的选择。
from tempfile import mkdtemp
import os.path as path

filename = path.join(mkdtemp(), 'tempfile.dat')

# now create a memory-mapped file with shape and data type 
# based on original R data frame:
A = NP.memmap(fpath, dtype="float32", mode="w+", shape=(150, 5))

# methods are ' flush' (writes to disk any changes you make to the array), and 'close'
# to write data to the memmap array (acdtually an array-like memory-map to 
# the data stored on disk)
A[:] = somedata[:]

1
谢谢Doug!这也是我已经解决的方案——唯一的问题是生成的文件超过50MB,这还算可以,但似乎有点笨重!我希望rpy2绑定能让我编写一个函数,它可以说“array,colnames,rownames = from_df(”data.frame()“)。 - Mike Dewar
1
在这种情况下(大数据),我会使用NumPy的内存映射数据结构,以避免将整个数据加载到RAM中。编辑我的答案并附上示例。 - doug

4
为什么要使用'data.frame',而不是使用'exprs(immgen)'返回的矩阵,如果您最终目标是将数据存储在矩阵中?
将矩阵传递给numpy非常简单(甚至可以在不复制的情况下完成): http://rpy.sourceforge.net/rpy2/doc-2.1/html/numpy.html#from-rpy2-to-numpy 这比通过文本表示数值数据以交换数据的建议更加简单和高效。
您似乎正在使用bioconductor类进行工作,并且可能对以下内容感兴趣: http://pypi.python.org/pypi/rpy2-bioconductor-extensions/

啊,你说得对。这是一个矩阵。太棒了,谢谢。为了让解决方案更清晰,我可以这样做: e = np.array(robjects.r('exprs(immgen)')) 现在e是一个包含所有浮点数的numpy数组。谢谢Laurent!我对bioC rpy2的东西很感兴趣,但无法安装。也许可以在支持列表中提问... - Mike Dewar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接