2016-03-03 5 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 

Я запустил это в функцию и применил его в пар. allel, но он все еще слишком медленный для того, для чего мне это нужно.

Я уже попробовал h2o.importFolder из замечательного h2o пакета, но это на самом деле гораздо медленнее по сравнению с использованием обычного R с data.table. Возможно, есть способ ускорить рассылку файлов, но я не уверен. Из нескольких раз, когда я запускал это, я заметил, что распаковка файлов обычно занимает около 2/3 времени функции.

+0

Я получаю улучшенные скорости (по сравнению с вашим самым эффективным кодом до сих пор) с помощью 'read_tsv' из пакета« readr ». '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

Я только что отредактировал ответ. Также интересно, так как ОП имеет отличную тестовую среду ... –

+2

Отличный ответ! Используя этот метод, я смог намного быстрее читать и обобщать свои данные. Используя 8 ядер, я смог прочитать и обработать 696 000 файлов за 1,5 минуты, где до этого потребовалось 12 минут. Мне нужно будет масштабировать его до миллионов файлов, так что это огромная помощь! Могу ли я спросить, что делает часть кода «grep -v»^Day »? –

4

Узкое место может быть вызвано использованием вызова system() внешним приложением.

Вы должны попытаться использовать функции построения, чтобы извлечь архив. Этот ответ объясняет, как: Decompress gz file using R

6

R имеет возможность считывать gzip файлы изначально, используя функцию gzfile. Посмотрите, работает ли это.

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

Вы можете упростить это до 'rbindlist (lapply (dat.files, read.delim))', между прочим. +1. Это кажется быстрее, чем 'read_tsv'. – A5C1D2H2I1M1N2O1R2T1

+0

Это очень помогло. Теперь я могу читать 232 000 файлов за 12 минут вместо 18. Мне нужно, чтобы это было еще немного быстрее, но это отличный старт. –

 Смежные вопросы

  • Нет связанных вопросов^_^