2012-03-23 1 views
8

Ho 15 milioni di file CSV, ciascuno con due colonne (integer e float) e tra 5 e 500 righe. Ogni file simile a:Il modo più veloce per importare milioni di file in R?

3453,0.034 
31,0.031 
567,0.456 
... 

Attualmente, sto iterare su tutti i file, e l'utilizzo di read.csv() per importare ciascun file in una grande lista. Ecco una versione semplificata:

allFileNames = Sys.glob(sprintf("%s/*/*/results/*/*", dir)) 

s$scores = list() 

for (i in 1:length(allFileNames)){ 
     if ((i %% 1000) == 0){ 
      cat(sprintf("%d of %d\n", i, length(allFileNames))) 
     } 

     fileName = allFileNames[i] 
     approachID = getApproachID(fileName) 
     bugID = getBugID(fileName) 

     size = file.info(fileName)$size 
     if (!is.na(size) && size > 0){ # make sure file exists and is not empty 
      tmp = read.csv(fileName, header=F, colClasses=c("integer", "numeric")) 
      colnames(tmp) = c("fileCode", "score") 
      s$scores[[approachID]][[bugID]] = tmp 
     } else { 
      # File does not exist, or is empty. 
      s$scores[[approachID]][[bugID]] = matrix(-1, ncol=2, nrow=1) 
     } 
    } 

tmp = read.csv(fileName, header=F, colClasses=c("integer", "numeric") 

Più tardi nel mio codice, vado indietro attraverso ogni matrice nella lista, e calcolare alcuni parametri.

Dopo aver avviato questo processo di importazione, sembra che richieda l'ordine da 3 a 5 giorni per il completamento. C'è un modo più veloce per farlo?

EDIT: Ho aggiunto ulteriori dettagli sul mio codice.

+1

possibile duplicato del [rapida lettura tabelle molto grandi come dataframes in R] (http://stackoverflow.com/questions/1727772/quickly-reading-very-large-tables-as-dataframes-in-r) – joran

+1

Che cosa stai cercando di fare? Crea una singola matrice con tutti i dati, oppure leggi ed elabora separatamente ciascuna matrice? –

+0

Questo è rilevante per il caricamento di molti file contemporaneamente: http://stackoverflow.com/questions/3764292/ – Ben

risposta

6

Utilizzando scan (come lo stato Joshua nel commento) potrebbe essere più veloce (3-4 volte):

scan(fileName, what=list(0L,0.0), sep=",", dec=".", quiet=TRUE) 

differenza principale è che la lista scan torna con due elementi e read.csv rendimenti data.frame.

+0

Stavo pensando qualcosa del tipo: 'List [[1]] <- matrix (scan (fileName, what = 0, sep =", "), ncol = 2, byrow = TRUE)'. –

+1

Grazie ragazzi. Come ho menzionato in un altro commento, passando a '' tmp <- matrix (scan (fileName, what = 0, sep = ",", quiet = T), ncol = 2, byrow = TRUE) '', il mio codice è correndo circa il doppio più velocemente. Dopo aver fatto un '' system.time() '', sembra che la maggior parte del tempo richiesto sia in IO, quindi suppongo che dovrò solo aspettare un po '. – stepthom

7

Io non sono chiare sul vostro obiettivo, ma se si sta cercando di leggere tutti questi file in un'unica struttura di dati R, poi vedo due principali problemi di prestazioni: tempi di accesso

  1. File - dal momento in cui richiedi read.csv, una miriade di processi complessi si avvia sulla tua macchina implicando vedere se quel file esiste, trovando la posizione di quel file in memoria o su disco (e leggendo i dati in memoria, se necessario), quindi interpretando i dati all'interno di R. Mi aspetterei che questo sarebbe un rallentamento quasi costante mentre leggi milioni di file.
  2. Crescere la singola struttura dati con ogni nuovo file letto. Ogni volta che si desidera aggiungere alcune righe alla matrice, è probabile che sia necessario ridistribuire un blocco di memoria di dimensioni simili per archiviare la matrice più grande. Se stai ingrandendo il tuo array 15 milioni di volte, noterai sicuramente un rallentamento delle prestazioni qui. Con questo problema, le prestazioni peggioreranno progressivamente man mano che leggi altri file.

Quindi, fare un po 'di profilazione rapida e vedere quanto durano le letture. Se stanno rallentando progressivamente mentre leggi altri file, concentriamoci sul problema n. 2. Se è costantemente lento, allora preoccupiamoci del problema numero 1.

soluzioni per quanto riguarda, direi che si potrebbe iniziare con due cose:

  1. combinare i file CSV in un altro linguaggio di programmazione. Un semplice script di shell probabilmente farebbe il lavoro per te se stai semplicemente collegando i file e concatenandoli in un unico file di grandi dimensioni. Come Joshua e Richie menzionano di seguito, potresti essere in grado di ottimizzare ciò senza doverti deviare in un'altra lingua utilizzando le più efficienti funzioni scan() o readlines().
  2. Pre-dimensiona la struttura dati unificata. Se utilizzi una matrice, ad esempio, imposta il numero di righe su ~ 15 milioni x 100. In questo modo dovrai solo trovare spazio nella memoria per questo oggetto una sola volta e il resto delle operazioni inserirà solo i dati nella matrice pre-dimensionata.

Aggiungi qualche altro dettaglio del tuo codice (che aspetto ha l'elenco che stai usando?) E potremmo essere in grado di essere più utile.

+3

Si noti inoltre che 'scan' è più appropriato di' read.csv' poiché i dati potrebbero essere tutti memorizzati come numerici. –

+0

O forse anche 'readLines' +' writeLines' se OP vuole solo combinare i file in uno solo. –

+0

@Jeff - Grazie per questa risposta dettagliata. Non penso di poter combinare tutti i file in uno solo, perché ho bisogno che vengano separati per le successive analisi. (Ogni file rappresenta un'esecuzione del mio esperimento.) Per quanto riguarda la preallocazione della mia struttura dati, c'è modo di preallocare la dimensione della mia lista ('' s $ scores'')? A proposito, non vedo peggiorare il rallentamento, quindi penso che le prestazioni siano dominate dall'IO del disco. – stepthom

0

Come diceva Jeff, ci sono molte cose qui che potrebbero richiedere molto tempo. Il problema potrebbe essere l'accesso ai file, la lettura dei file o l'esaurimento della memoria quando nella RAM sono presenti 15 milioni di frame di dati.Per aggravare il problema, il collo di bottiglia potrebbe variare a seconda delle specifiche della tua macchina (ad esempio, un disco rigido lento rallenterà la lettura dei file, la mancanza di RAM sarà un problema con un numero elevato di file). Per capire il problema, dovrai fare un po 'di profilazione.

Prova a leggere solo in 10000 o più file per iniziare e chiamando system.time o, più sofisticato, utilizzando rbenchmark per vedere ciò che richiede più tempo.

Poi sguardo al collegamento di Joran

Quickly reading very large tables as dataframes in R

e vedere se uno della tecnica ci si aiuta.

2

Come su questo flusso di lavoro generale? Non testato, però.

my.list.of.files <- list.files(pattern = ".txt") # char vector of filenames 
my.data <- sapply(my.list.of.files, FUN = function(x) { 
      # read file using scan, craft the output to two columns 
     }) # result is merged 

#or if you use simplify= FALSE 
my.data <- sapply(my.list.of.files, FUN = function(x) { 
      # read file using scan (or some other method), craft the output to two columns 
     }, simplify = FALSE) #you get a list 
my.data <- do.call("rbind", my.data) 
+0

So che questo è solo un modello, ma tieni presente che se avessi tutti i 15 milioni di file in una singola directory, anche questa potrebbe essere un'altra causa delle tue prestazioni. –

+1

Nota che 'sapply' è un po 'lento perché R deve fare del lavoro extra per capire come semplificare l'output. Della famiglia '* apply',' lapply' è la più veloce, quindi forse più appropriata qui. – flodel

+0

@Jeff, questo non è qualcosa che possiamo spiegare. @flodel, anche quando si specifica 'simplify = FALSE'? –