2010-04-19 14 views
7

Tengo un data.frame en R. Contiene una gran cantidad de datos: niveles de expresión génica de muchas (125) matrices. Me gustaría que los datos en Python, debido principalmente a mi incompetencia en R y el hecho de que se suponía que era un trabajo de 30 minutos.rpy2: Convertir un data.frame en una matriz numpy

Me gustaría que el siguiente código funcione. Para entender este código, sepa que la variable path contiene la ruta completa a mi conjunto de datos que, cuando se carga, me da una variable llamada immgen. Sepa que immgen es un objeto (un objeto Bioconductor ExpressionSet) y que exprs(immgen) devuelve un marco de datos con 125 columnas (experimentos) y decenas de miles de filas (genes nombrados). (Sólo en caso de que no está claro, se trata de código Python, utilizando robjects.r llamar código 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) 

Este código se ejecuta, pero expression_data es simplemente array([[1]]).

estoy bastante seguro de que e no representa la trama de datos generada por exprs() debido a cosas como:

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

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

Pero, de nuevo ¿quién sabe? Incluso si e representara mi data.frame, que no se convierta directamente en una matriz sería lo suficientemente justo - un marco de datos tiene más que una matriz (nombres de fila y colnames) y así quizás la vida no debería ser tan fácil . Sin embargo, todavía no puedo encontrar la forma de realizar la conversión. La documentación es demasiado escueta para mí, aunque mi comprensión limitada de los títulos en los documentos implica que esto debería ser posible.

¿Alguien tiene alguna idea?

Respuesta

4

¿Por qué pasar por un data.frame cuando 'exprs (immgen)' devuelve a/matrix/y su objetivo final es tener sus datos en una matriz?

Al pasar la matriz a numpy es sencillo (e incluso se puede hacer sin hacer una copia): http://rpy.sourceforge.net/rpy2/doc-2.1/html/numpy.html#from-rpy2-to-numpy

Esto debe superar tanto en la simplicidad y eficiencia la sugerencia de ir a través de la representación de texto de los datos numéricos en archivos planos como una forma de intercambiar datos.

Usted parece ser la utilización de clases Bioconductor, y podría estar interesado en los siguientes: http://pypi.python.org/pypi/rpy2-bioconductor-extensions/

+0

argh tienes razón. Es una matriz. Eso es genial, gracias. Solo para que la solución sea clara, puedo hacerlo: e = np .array (robjects.r ('exprs (immgen)')) y ahora e es una matriz numpy con todos mis números de coma flotante. Gracias Laurent. Estoy interesado en las cosas de bioC rpy2, pero no puedo conseguirlo para instalar. Una pregunta para la lista de soporte aunque tal vez ... –

7

Esta es la manera más directa y confiable que he encontrado para transferir un marco de datos de R a Python.

Para empezar, creo que el intercambio de datos a través de los enlaces R es una complicación innecesaria. R proporciona un método simple para exportar datos, del mismo modo, NumPy tiene métodos decentes para la importación de datos. El formato de archivo es la única interfaz común requerida aquí.

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. ]] 

De acuerdo con la documentación (y mi propia experiencia de lo que vale la pena) loadtxt es el método preferido para la importación de datos convencional.

También se puede pasar a loadtxt una tupla de tipos de datos (el argumento es dtypes), un elemento de la tupla para cada columna. Observe 'skiprows = 1' para pasar los encabezados de las columnas (para loadtxt las filas están indexadas desde 1, columnas desde 0).

Finalmente, convertí el factor de marco de datos a entero (que en realidad es el tipo de datos subyacente para factor) antes de exportar - 'unclass' es probablemente la forma más fácil de hacerlo.

Si tiene datos grandes (es decir, no quieren cargar todo el archivo de datos en la memoria, pero todavía tienen que acceder a ella) estructura de datos asignado a la memoria de NumPy ('memmap') es una buena opción:

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

Gracias Doug! Esta es la solución en la que también me había acostumbrado: el único problema es que los archivos resultantes tienen + 50MB, lo que está bastante bien, ¡pero parece un poco torpe! Quiero que los enlaces rpy2 me permitan escribir una función que diga 'array, colnames, rownames = from_df (" data.frame() "'. –

+1

en ese caso (big data) solo usaría los datos mapeados en memoria de NumPy estructura, para evitar cargar todo en RAM. Edición de mi respuesta con ejemplo – doug

Cuestiones relacionadas