2009-12-28 12 views
22

Mi chiedo se ci sia qualche documentazione sull'efficienza delle operazioni in R, in particolare quelle relative alla manipolazione dei dati.Efficienza delle operazioni sulle strutture di dati R

Ad esempio:

  • immagino che sia efficiente per aggiungere colonne a una cornice di dati, perché sto indovinando sei solo l'aggiunta di un elemento di una lista collegata.
  • Immagino che l'aggiunta di righe sia più lenta perché i vettori sono contenuti negli array allo C level e devi allocare una nuova matrice di lunghezza n+1 e copiare tutti gli elementi.

Gli sviluppatori probabilmente non vogliono legarsi a un'implementazione particolare, ma sarebbe bello avere qualcosa di più solido di quello che si suppone di andare avanti.

Inoltre, so che l'hint principale delle prestazioni di R consiste nell'utilizzare le operazioni vettoriali quando possibile, diversamente da loops.

  • E i vari gusti di apply?
  • quelli sono solo hidden loops?
  • Che dire di matrices rispetto a data frames?
+0

Per informazioni più recenti sulle prestazioni R, l'Advanced R di Hadley Wickham ha una sezione informativa su [performance] (http://adv-r.had.co.nz/Performance.html) e Jeffrey Horner ha scritto un paio di fantastici post su [Hash Table Performance in R] (http://jeffreyhorner.tumblr.com/post/114524915928/hash-table-performance-in-r-part-i). – cbare

risposta

27

Data era una delle caratteristiche ho esaminato prima che impegnato nell'apprendimento R. Per meglio o peggio, qui ci sono le mie osservazioni e soluzioni/palliativi su questi temi:

1. che R non gestisce i dati di grandi (> 2 GB?) Per me questo è un termine improprio. Per impostazione predefinita, le funzioni di input dei dati comuni caricano i dati nella RAM. Non per essere disinvolto, ma per me, questa è una caratteristica non un bug - ogni volta che i miei dati si adatteranno alla mia RAM disponibile, è lì che lo voglio. Allo stesso modo, una delle funzionalità più popolari di SQLite è l'opzione in memoria: l'utente ha la semplice possibilità di caricare l'intero dB nella RAM. Se i tuoi dati non si adattano alla memoria, allora R lo rende sorprendentemente facile da persistere, tramite connessioni ai comuni sistemi RDBMS (RODBC, RSQLite, RMySQL, ecc.), Tramite opzioni senza fronzoli come il pacchetto filehash e via sistemi che utilizzano le attuali tecnologie/pratiche (ad esempio, posso consigliare ff). In altre parole, gli sviluppatori R hanno scelto un valore ragionevole (e probabilmente ottimale) predefinito, dal quale è molto facile rinunciare.

2. Le prestazioni di read.table (read.csv, read.delim, et al.), I mezzi più comuni per ottenere dati in R, possono essere migliorate 5 volte (e spesso molto di più nella mia esperienza) semplicemente disattivando alcuni degli argomenti predefiniti di read.table - quelli che hanno il maggior effetto sulle prestazioni sono menzionati nella Guida di R (? read.table). In breve, gli sviluppatori R ci dicono che se fornisci valori per i parametri 'colClasses', 'nrows', 'sep' e 'comment.char' (in particolare, passa in '' se sai che il tuo file inizia con intestazioni o dati sulla linea 1), vedrai un significativo aumento delle prestazioni. Ho trovato che sia vero.

Qui ci sono i frammenti che uso per quei parametri:

Per ottenere il numero di righe nel file di dati (forniscono questo frammento come argomento per il parametro, 'nrows', nella chiamata a read.table):

as.numeric((gsub("[^0-9]+", "", system(paste("wc -l ", file_name, sep=""), intern=T)))) 

per ottenere le classi per ogni colonna:

function(fname){sapply(read.table(fname, header=T, nrows=5), class)} 

Nota: non è possibile passare questo frammento come argomento, si deve chiamare per primo, poi passare il valore macerare urna - in altre parole, chiamare la funzione, associare il valore restituito a una variabile e quindi passare la variabile come valore al parametro 'colClasses' nella chiamata a read.table:

3. Utilizzo di Scan. Con un po 'più di fastidio, puoi fare di meglio (ottimizzando' read.table ') usando' scan 'invece di' read.table '(' read.table 'è in realtà solo un wrapper di' scan '). Ancora una volta, è molto facile da fare. Io uso 'scan' per inserire ogni colonna individualmente e poi costruisco il mio data.frame all'interno di R, cioè df = data.frame (cbind (col1, col2, ....)).

4. Utilizzare i contenitori R per la persistenza al posto dei formati di file ordinari (ad es., 'Txt', 'csv'). File di dati nativi di R '.RData 'è un formato binario un po' più piccolo di un file di dati txt compresso ('.gz'). Li crei usando risparmi (,). Si carica nuovamente nello spazio dei nomi R con carico(). La differenza nei tempi di caricamento rispetto a "read.table" è drammatica. Per esempio, w/a 25 file di MB (dimensioni non compresse)

system.time(read.table("tdata01.txt.gz", sep=",")) 
=> user system elapsed 
    6.173 0.245 **6.450** 

system.time(load("tdata01.RData")) 
=> user system elapsed 
    0.912 0.006 **0.912** 

5. Prestare attenzione ai tipi di dati spesso può dare un incremento delle prestazioni e ridurre l'occupazione di memoria. Questo punto è probabilmente più utile nell'ottenere dati da R. Il punto chiave da tenere presente qui è che, per impostazione predefinita, i numeri nelle espressioni R vengono interpretati come virgola mobile a precisione doppia, ad esempio,> typeof (5) restituisce "double". " Confronta la dimensione dell'oggetto di una matrice di dimensioni ragionevoli di ciascuna e puoi vedere il significato (usa object.size()). Quindi costringi a numero intero quando puoi.

Infine, la famiglia di funzioni "apply" (tra le altre) non sono "loop nascosti" o loop wrapper. Sono loop implementati in C - grande differenza in termini di prestazioni. [edit: AWB ha correttamente sottolineato che mentre 'sapply', 'tapply' e 'mapply' sono implementati in C, 'apply' è semplicemente una funzione wrapper.

+4

Vorrei correggere un'istruzione nel post di doug (altrimenti eccellente) e indicare un buon riferimento sulla velocità di I/O dei dati. In primo luogo, non tutte le funzioni 'apply' sono implementate in C. 'lapply' è implementato in C, così come 'sapply' (che racchiude 'lapply'). 'mapply' è anche implementato in C. 'apply', tuttavia, è semplicemente un buon wrapper per 'for'; lo stesso vale per le funzioni nell'eccellente pacchetto "plyr". In secondo luogo, controllare questa voce nel blog Revolutions per ulteriori informazioni sull'efficienza IO: http://blog.revolution-computing.com/2009/12/speedreading-files-revisited.html – AWB

+0

Grazie per la correzione AWB - my risposta modificata per riflettere i tuoi commenti. – doug

+0

Non seguo il tuo primo punto: stai dicendo che R gestisce o non gestisce i big data? Certamente lo fa (come fai notare), quindi forse lo stai affermando come una comune percezione sbagliata da parte degli altri? – Iterator

11

Queste cose appaiono sugli elenchi, in particolare su r-devel. Una pepita abbastanza ben consolidata è quella ad es. Le operazioni matrix tendono ad essere più veloci delle operazioni data.frame. Poi ci sono pacchetti aggiuntivi che funzionano bene - il pacchetto data.table di Matt è piuttosto veloce e Jeff ha ottenuto l'indicizzazione xts per essere veloce.

Ma "tutto dipende", quindi di solito si consiglia il valore al profilo sul codice specifico. R ha un sacco di supporto per la creazione di profili, quindi dovresti usarlo. Il mio Intro to HPC with R tutorials ha un numero di esempi di profilo.

6

Proverò a tornare e fornire maggiori dettagli. Se hai qualche domanda sull'efficienza di un'operazione rispetto a un'altra, farebbe meglio a profilare il tuo codice (come suggerisce Dirk). La funzione system.time() è il modo più semplice per eseguire questa operazione sebbene esistano molte utilità più avanzate (ad esempio Rprof, come documentato here).

una risposta rapida per la seconda parte della tua domanda:

Che dire dei vari sapori di applicare? Sono solo loop nascosti?

Per la maggior parte sì, le funzioni di applicazione sono solo cicli e possono essere più lente delle istruzioni for. Il loro principale vantaggio è un codice più chiaro. L'eccezione principale che ho trovato è lapply che può essere più veloce perché è codificata in C direttamente.

E per quanto riguarda le matrici contro i frame di dati?

Le matrici sono più efficienti dei frame di dati perché richiedono meno memoria per l'archiviazione. Questo perché i frame di dati richiedono dati di attributi aggiuntivi. Da R Introduction:

A può frame di dati per vari scopi essere considerato come una matrice con colonne possibilmente di differenti meccanismi e attributi

IO
Problemi correlati