2016-03-03 51 views
12

Ho poche centinaia di migliaia di piccoli file .dat.gz che voglio leggere in R nel modo più efficiente possibile. Ho letto il file e poi ho immediatamente aggregato e scartato i dati, quindi non sono preoccupato di gestire la memoria man mano che mi avvicino alla fine del processo. Voglio davvero accelerare il collo di bottiglia, che accade per decomprimere e leggere i dati.Il modo più veloce di leggere in 100.000 file .dat.gz

Ogni set di dati è costituito da 366 righe e 17 colonne. Ecco un esempio riproducibile di quello che sto facendo finora:

Costruire dati riproducibili:

require(data.table) 

# Make dir 
system("mkdir practice") 

# Function to create data 
create_write_data <- function(file.nm) { 
    dt <- data.table(Day=0:365) 
    dt[, (paste0("V", 1:17)) := lapply(1:17, function(x) rnorm(n=366))] 
    write.table(dt, paste0("./practice/",file.nm), row.names=FALSE, sep="\t", quote=FALSE) 
    system(paste0("gzip ./practice/", file.nm))  
} 

E qui è il codice di applicazione:

# Apply function to create 10 fake zipped data.frames (550 kb on disk) 
tmp <- lapply(paste0("dt", 1:10,".dat"), function(x) create_write_data(x)) 

E qui è il mio codice più efficiente finora leggere nei dati:

# Function to read in files as fast as possible 
read_Fast <- function(path.gz) { 
    system(paste0("gzip -d ", path.gz)) # Unzip file 
    path.dat <- gsub(".gz", "", path.gz) 
    dat_run <- fread(path.dat) 
} 

# Apply above function 
dat.files <- list.files(path="./practice", full.names = TRUE) 
system.time(dat.list <- rbindlist(lapply(dat.files, read_Fast), fill=TRUE)) 
dat.list 

Ho imbottigliato in una funzione e l'ho applicato in allel, ma è ancora troppo lento per ciò di cui ho bisogno.

Ho già provato il h2o.importFolder dal pacchetto meraviglioso h2o, ma in realtà è molto molto più lento rispetto all'utilizzo di pianura R con data.table. Forse c'è un modo per accelerare la decompressione dei file, ma non sono sicuro. Dalle poche volte che l'ho eseguito, ho notato che la decompressione dei file richiede in genere circa 2/3 del tempo di funzionamento.

+0

Sto migliorando le velocità (rispetto al codice più efficiente finora) utilizzando 'read_tsv' dal pacchetto" readr ". 'rbindlist (lapply (dat.files, read_tsv))' – A5C1D2H2I1M1N2O1R2T1

risposta

11

Sono quasi sorpreso che ciò abbia funzionato. Spero che funzioni per il tuo caso. Sono piuttosto curioso di sapere come la velocità paragona alla lettura in dati compressi dal disco direttamente da R (anche se con una penalità per non-vectorization).

tblNames = fread('cat *dat.gz | gunzip | head -n 1')[, colnames(.SD)] 
tbl = fread('cat *dat.gz | gunzip | grep -v "^Day"') 
setnames(tbl, tblNames) 
tbl 
+2

Sorpreso anche. È incredibile Qualche idea su come si confronta in termini di velocità con gli altri metodi? – Arun

+0

Ho appena modificato la risposta. Chiedo pure, come l'OP ha un ambiente di test eccellente ... –

+2

Ottima risposta! Utilizzando questo metodo, sono stato in grado di leggere e aggregare i miei dati molto più velocemente. Usando 8 core, sono stato in grado di leggere ed elaborare 696.000 file in 1.5 minuti, mentre prima richiedevano 12 minuti. In futuro dovrò ridimensionarlo a milioni di file, quindi questo è di grande aiuto! Posso chiederti cosa sta facendo la parte 'grep -v"^Day "' del codice? –

4

Il collo di bottiglia potrebbe essere causato dall'utilizzo della chiamata di sistema() a un'applicazione esterna.

Si dovrebbe provare a utilizzare le funzioni incorporate per estrarre l'archivio. Questa risposta spiega come: Decompress gz file using R

6

R è in grado di leggere i file compressi con gzip in modo nativo, utilizzando la funzione gzfile. Vedi se questo funziona.

rbindlist(lapply(dat.files, function(f) { 
    read.delim(gzfile(f)) 
})) 
+1

Puoi comunque semplificarlo con 'rbindlist (lapply (dat.files, read.delim))', a proposito. +1. Questo sembra più veloce di 'read_tsv' anche. – A5C1D2H2I1M1N2O1R2T1

+0

Questo ha aiutato un bel po '. Ora sono in grado di leggere 232.000 file in 12 minuti invece di 18. Ho bisogno che questo sia ancora un po 'più veloce, ma questo è un ottimo inizio –