2012-01-30 5 views
8

Lettura ~ 5x10^6 i valori numerici in R da un file di testo sono relativamente lenti sulla mia macchina (alcuni secondi e ho letto molti di questi file), anche con scan(..., what="numeric", nmax=5000) o trucchi simili. Potrebbe essere utile provare un wrapper Rcpp per questo tipo di attività (ad esempio, Armadillo ha alcune utilità per leggere i file di testo)? O probabilmente sprecherei il mio tempo per un guadagno minimo o nullo nelle prestazioni a causa di un sovraccarico previsto dell'interfaccia? Non sono sicuro di cosa stia limitando la velocità (prestazioni intrinseche della macchina o altro?) È un'attività che ripeto molte volte al giorno, in genere, e il formato del file è sempre lo stesso, 1000 colonne, circa 5000 righe.più veloce di scan() con Rcpp?

Ecco un file di esempio con cui giocare, se necessario.

nr <- 5000 
nc <- 1000 

m <- matrix(round(rnorm(nr*nc),3),nr=nr) 

cat(m[1, -1], "\n", file = "test.txt") # first line is shorter 
write.table(m[-1, ], file = "test.txt", append=TRUE, 
      row.names = FALSE, col.names = FALSE) 

Aggiornamento: ho provato read.csv.sql e anche load("test.txt", arma::raw_ascii) utilizzando Armadillo ed entrambi erano più lenti rispetto alla soluzione scan.

+3

Prova 'read.csv.sql' in sqldf e vedere se questo è più veloce. È solo una riga di codice. http://sqldf.googlecode.com –

+0

Ho provato 'system.time (b <- read.csv.sql ("test.txt", intestazione = FALSE, settembre =" "))' ed era più lento di 'sistema .time (a <- scan ("test.txt", cosa = "numerico")) '. Inoltre, penso che la conservazione dei dati in una matrice dovrebbe essere più efficiente di in un 'data.frame' – baptiste

risposta

8

Consiglio vivamente di verificare fread nell'ultima versione di data.table. La versione su CRAN (1.8.6) non ha ancora fread (al momento di questo post) quindi dovresti essere in grado di ottenerla se installi dalla sorgente più recente su R-forge. Vedi here.

+0

che è davvero molto più veloce, grazie! – baptiste

5

Si prega di tenere presente che non sono un esperto di R ma forse il concetto si applica anche qui: in genere la lettura di materiale binario è molto più veloce della lettura di file di testo. Se i tuoi file sorgente non cambiano frequentemente (ad esempio stai utilizzando versioni diverse del tuo script/programma sugli stessi dati), prova a leggerli tramite scan() una volta e memorizzali in un formato binario (il manuale ha un capitolo su esportazione di file binari). Da lì in poi è possibile modificare il programma per leggere l'input binario.

@Rcpp: scan() & è probabile che gli amici chiamino un'implementazione nativa (come fscanf()), quindi la scrittura delle proprie funzioni di lettura file tramite Rcpp potrebbe non fornire un enorme guadagno in termini di prestazioni. Puoi comunque provarlo (e ottimizzare per i tuoi dati particolari).

+0

re Rcpp, sì, questa è la mia preoccupazione: la sua attuazione solo per vedere che esegue lo stesso' scan() '. Speravo che qualcuno potesse averlo già capito. – baptiste

+0

Mi aspetterei che fosse molto più veloce, ma ovviamente meno generale. –

3

Sì, quasi sicuramente puoi creare qualcosa che vada più veloce di read.csv/scan. Tuttavia, per la lettura di file ad alte prestazioni ci sono alcuni trucchi esistenti che ti consentono già di andare molto più velocemente, quindi qualsiasi cosa tu faccia sarebbe in competizione con quelli.

Come ha fatto notare Mathias, se i file non cambiano molto spesso, è possibile memorizzarli nella cache chiamando save, quindi ripristinarli con load. (Assicurati di utilizzare ascii = FALSE, poiché la lettura dei file binari sarà più veloce.)

In secondo luogo, come Gabor ha menzionato, è possibile ottenere spesso un notevole incremento delle prestazioni leggendo il file in un database e quindi da tale database in R.

In terzo luogo, è possibile utilizzare il pacchetto HadoopStreaming di utilizzare le capacità di lettura di file di Hadoop.

Per ulteriori informazioni su queste tecniche, vedere Quickly reading very large tables as dataframes in R.

+0

grazie. Penso di aver usato tutti i suggerimenti da quel thread SO, e no, salvare i dati come '.rda' o altrimenti non è un'opzione in quanto è la prima importazione che mi dà fastidio. Controllerò 'sqldf', che avrei brevemente considerato, ma la sintassi mi ha confuso. – baptiste

4

Salut Baptiste,

ingresso/uscita dati è un argomento enorme, così grande che R dotato di una propria manual on data input/output.

Le funzioni di base di R possono essere lente perché sono molto generiche. Se conosci il tuo formato, puoi facilmente scrivere un adattatore di importazione più veloce. Se conosci anche le tue dimensioni, è ancora più semplice in quanto hai bisogno di una sola allocazione di memoria.

Modifica: Come prima approssimazione, vorrei scrivere un dieci-liner C++.Apri un file, leggi una riga, suddividila in token, assegna a uno vector<vector<double> > o qualcosa del genere. Anche se usi push_back() su singoli elementi vettoriali, dovresti essere competitivo con scan(), methinks.

una volta ho avuto un pulito di classe piccola csv reader in C++ basato sul codice di Brian Kernighan se stesso. Abbastanza generico (per i file CSV), abbastanza potente.

È possibile quindi spremere prestazioni, come si vede in forma.

Ulteriore modifica: Questo SO question ha un numero di puntatori per il caso di lettura di csv e riferimenti al libro di Kernighan e Plauger.

+0

Non conosco l'esatta dimensione (beh, qualche strumento unix potrebbe scoprire), ma 5000 è una buona stima approssimativa superiore – baptiste