2016-03-03 14 views
12

Tôi có một vài trăm nghìn tệp rất nhỏ .dat.gz mà tôi muốn đọc vào R theo cách hiệu quả nhất có thể. Tôi đọc trong tập tin và sau đó ngay lập tức tổng hợp và loại bỏ các dữ liệu, vì vậy tôi không lo lắng về việc quản lý bộ nhớ khi tôi nhận được gần cuối của quá trình. Tôi thực sự muốn tăng tốc độ tắc nghẽn, điều này xảy ra để giải nén và đọc dữ liệu.Cách nhanh nhất để đọc trong 100.000 tệp .dat.gz

Mỗi tập dữ liệu bao gồm 366 hàng và 17 cột. Dưới đây là một ví dụ tái sản xuất những gì tôi đang làm cho đến nay:

Xây dựng dữ liệu tái sản xuất:

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

Và đây là mã áp dụng:

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

Và đây là mã hiệu quả nhất của tôi cho đến nay để đọc trong dữ liệu:

# 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 

Tôi đã đóng gói chức năng này và áp dụng nó ngang hàng allel, nhưng nó vẫn còn quá nhiều cho những gì tôi cần này cho.

Tôi đã thử các h2o.importFolder từ gói h2o tuyệt vời, nhưng nó thực sự chậm hơn nhiều so với sử dụng đồng bằng R với data.table. Có lẽ có một cách để tăng tốc độ giải nén các tập tin, nhưng tôi không chắc chắn. Từ vài lần mà tôi đã chạy điều này, tôi đã nhận thấy rằng việc giải nén các tập tin thường mất khoảng 2/3 của thời gian chức năng.

+0

Tôi đang nhận được tốc độ cải thiện (so với mã hiệu quả nhất cho đến nay) bằng cách sử dụng 'read_tsv' từ gói" readr ". 'rbindlist (lapply (dat.files, read_tsv))' – A5C1D2H2I1M1N2O1R2T1

Trả lời

11

Tôi ngạc nhiên vì điều này thực sự hiệu quả. Hy vọng rằng nó hoạt động cho trường hợp của bạn. Tôi khá tò mò muốn biết làm thế nào tốc độ so sánh để đọc dữ liệu nén từ đĩa trực tiếp từ R (mặc dù với một hình phạt cho non-vectorization) để thay thế.

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

Ngạc nhiên quá. Thật đáng kinh ngạc. Bất kỳ ý tưởng như thế nào nó so sánh về tốc độ cho các phương pháp khác? – Arun

+0

Tôi vừa chỉnh sửa câu trả lời. Tự hỏi là tốt, như OP có một môi trường thử nghiệm tuyệt vời ... –

+2

Câu trả lời hay! Sử dụng phương pháp này, tôi đã có thể đọc và tổng hợp dữ liệu của mình nhanh hơn rất nhiều. Sử dụng 8 lõi, tôi đã có thể đọc và xử lý 696.000 tệp trong 1,5 phút, trước khi mất 12 phút. Tôi sẽ cần phải mở rộng quy mô này cho hàng triệu tệp, vì vậy đây là một trợ giúp lớn! Tôi có thể hỏi phần 'grep -v"^Day "' của mã đang hoạt động không? –

4

Nút cổ chai có thể do việc sử dụng hệ thống() gọi tới ứng dụng bên ngoài.

Bạn nên thử sử dụng các hàm dựng sẵn để trích xuất lưu trữ. Câu trả lời này giải thích cách thực hiện: Decompress gz file using R

6

R có khả năng đọc các tệp đã nén bằng cách sử dụng hàm gzfile. Xem nếu điều này hoạt động.

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

Bạn có thể đơn giản hóa nó thành 'rbindlist (lapply (dat.files, read.delim))', nhân tiện. +1. Điều này có vẻ nhanh hơn 'read_tsv'. – A5C1D2H2I1M1N2O1R2T1

+0

Điều này đã giúp khá nhiều. Tôi bây giờ có thể đọc trong 232.000 tập tin trong 12 phút thay vì 18. Tôi cần điều này để được khá nhanh hơn một chút vẫn còn, nhưng đây là một khởi đầu tuyệt vời –

Các vấn đề liên quan