2010-04-19 17 views
7

Ho un data.frame in R. Contiene molti dati: i livelli di espressione genica da molti (125) array. Mi piacerebbe i dati in Python, dovuti principalmente alla mia incompetenza in R e al fatto che questo doveva essere un lavoro di 30 minuti.rpy2: Conversione di un data.frame in una matrice numpy

Vorrei il seguente codice per funzionare. Per capire questo codice, sappi che la variabile path contiene il percorso completo del mio set di dati che, quando caricato, mi dà una variabile chiamata immgen. Sapere che immgen è un oggetto (un oggetto Bioconductor ExpressionSet) e che exprs(immgen) restituisce un frame di dati con 125 colonne (esperimenti) e decine di migliaia di righe (denominate geni). (Solo nel caso non si capisce bene, questo è il codice Python, utilizzando robjects.r per chiamare il codice 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) 

Questo codice viene eseguito, ma è semplicemente expression_dataarray([[1]]).

Sono abbastanza sicuro che e non rappresenta la cornice di dati generato da exprs() a causa di cose come:

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

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

Ma poi chi lo sa? Anche se e rappresentasse il mio data.frame, che non converta direttamente in un array sarebbe abbastanza equo - un frame di dati ha più in esso di un array (rownames e colnames) e quindi forse la vita non dovrebbe essere così facile . Tuttavia non riesco ancora a capire come eseguire la conversione. La documentazione è un po 'troppo concisa per me, anche se la mia comprensione limitata dei titoli dei documenti implica che ciò dovrebbe essere possibile.

Qualche idea?

risposta

4

Perché passare attraverso un data.frame quando 'exprs (immgen)' restituisce una matrice// e il tuo obiettivo finale è avere i dati in una matrice?

Passando matrice per NumPy è semplice (e può anche essere realizzato senza una copia): http://rpy.sourceforge.net/rpy2/doc-2.1/html/numpy.html#from-rpy2-to-numpy

Ciò dovrebbe battere sia semplice ed efficiente il suggerimento di passare attraverso rappresentazione testuale di dati numerici in file flat come un modo per scambiare dati.

Lei sembra di lavorare con le classi Bioconductor, e potrebbe essere interessato al seguente: http://pypi.python.org/pypi/rpy2-bioconductor-extensions/

+0

argh hai ragione, è una matrice.Questo è brillante, grazie.Ma solo la soluzione è chiara, posso fare: e = np .array (robjects.r ('exprs (immgen)')) e ora e è un array numpy con tutti i miei numeri in virgola mobile in esso. Grazie Laurent! Sono interessato alla roba di bioC rpy2, ma non riesco a ottenerlo installare. Una domanda per l'elenco di supporto anche se forse ... –

7

Questo è il modo più diretto e affidabile che ho trovato per trasferire un frame di dati da R a Python.

Per cominciare, penso che scambiare i dati attraverso le associazioni R sia una complicazione inutile. R fornisce un metodo semplice per esportare i dati, allo stesso modo, NumPy ha metodi decenti per l'importazione dei dati. Il formato del file è l'unica interfaccia comune richiesta qui.

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

secondo la documentazione (e la mia esperienza per quello che vale) loadtxt è il metodo preferito per l'importazione di dati convenzionali.

Si può anche passare per loadtxt una tupla di tipi di dati (l'argomento è dtypes), un elemento nella tupla per ogni colonna. Notare "skiprows = 1" per scavalcare le intestazioni delle colonne (per loadtxt le righe sono indicizzate da 1, colonne da 0).

Infine, ho convertito il fattore dataframe in intero (che è in realtà il tipo di dati sottostante per fattore) prima dell'esportazione: "unclass" è probabilmente il modo più semplice per farlo.

Se si dispone di dati di grandi dimensioni (ad esempio, non si vuole caricare l'intero file di dati in memoria, ma ancora bisogno di accedervi) struttura di dati mappato in memoria di NumPy ('memmap') è una buona scelta:

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

Grazie Doug! Questa è la soluzione su cui mi sono basato anche io - l'unico problema è che i file risultanti sono + 50MB, il che è abbastanza OK, ma sembra un tocco goffo! Mi piacerebbe che i binding di rpy2 mi permettessero di scrivere una funzione che dicesse 'array, colnames, rownames = from_df (" data.frame() "'. –

+1

in quel caso (big data) userei solo i dati mappati in memoria di NumPy struttura, per evitare di caricare l'intera cosa nella RAM Modifica la mia risposta con esempio – doug

Problemi correlati