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

7 投票
2 回答
6041 浏览
提问于 2025-04-15 21:47

我在R语言中有一个数据框,里面有很多数据:来自125个数组的基因表达水平。由于我在R方面的能力有限,而且这本来应该是个30分钟就能完成的工作,所以我想把数据转到Python中。

我希望以下代码能够正常工作。要理解这段代码,你需要知道变量path包含了我的数据集的完整路径,当我加载这个数据集时,会得到一个叫immgen的变量。immgen是一个对象(一个Bioconductor的ExpressionSet对象),而exprs(immgen)会返回一个数据框,这个数据框有125列(实验),还有成千上万行(命名的基因)。(为了避免误解,这段代码是Python代码,使用robjects.r来调用R代码)

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[:]
4

为什么要通过一个数据框(data.frame),而'exprs(immgen)'返回的是一个矩阵(matrix),而你的最终目标是把数据放在一个矩阵里呢?

把这个矩阵传给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/

撰写回答