2016-03-03 43 views
12

我有幾十萬個非常小的.dat.gz文件,我想以最有效的方式讀入R文件。我在文件中讀取數據,然後立即聚合並丟棄數據,因此我不擔心在接近過程結束時管理內存。我只是想加快瓶頸,而這正是解壓縮和讀取數據的過程。讀取100,000.dat.gz文件的最快方法

每個數據集由366行和17列組成。這裏是什麼,我到目前爲止做重複的例子:

建立可重複的數據:

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))  
} 

這裏是代碼應用:

# 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)) 

這裏是我最高效的代碼到目前爲止在數據中讀取:

# 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 

我已經裝入了一個函數,並將其應用於par等等,但對於我所需要的,它仍然太慢。

我已經嘗試從精彩的h2o包中獲得h2o.importFolder,但實際上它要比使用普通Rdata.table慢得多。也許有一種方法可以加速解壓縮文件,但我不確定。從我運行過的這幾次,我已經注意到,解壓縮文件通常需要大約2/3的功能時間。

+0

通過使用「readr」包中的'read_tsv',我得到了改進的速度(與迄今爲止最有效的代碼相比)。 'rbindlist(lapply(dat.files,read_tsv))' – A5C1D2H2I1M1N2O1R2T1

回答

11

我有點驚訝,這實際上工作。希望它適用於你的情況。我很好奇,知道如何將速度與直接從R讀取磁盤壓縮數據的速度進行比較(儘管存在對非矢量化的懲罰)。

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

也感到驚訝。這真太了不起了。任何想法在速度方面與其他方法的比較如何? – Arun

+0

我剛編輯答案。想知道,因爲OP有一個優秀的測試環境... –

+2

很好的答案!使用這種方法,我能夠更快地讀取和彙總數據。使用8個內核,我能夠在1.5分鐘內讀入並處理696,000個文件,在這之前花了12分鐘。接下來我需要將其擴展到數百萬個文件,所以這是一個巨大的幫助!我可以問一下'grep -v「^ Day \'部分代碼在做什麼? –

4

使用system()調用外部應用程序可能會導致瓶頸。

你應該嘗試使用builting功能來提取檔案。 此答案解釋瞭如何:Decompress gz file using R

6

R有能力使用gzfile函數本地讀取gzip文件。看看這是否有效。

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

順便說一句,你可以簡化爲'rbindlist(lapply(dat.files,read.delim))'。 +1。這似乎也比'read_tsv'更快。 – A5C1D2H2I1M1N2O1R2T1

+0

這確實有幫助。我現在能夠在12分鐘內讀取232,000個文件,而不是18個。我仍然需要這個更快的速度,但這是一個很好的開始 –

相關問題