Я прочитал большой файл .csv
в файл data.table
, используя fread
. На следующем этапе я выполняю некоторые операции по очистке данных, такие как преобразование некоторых символьных переменных в даты.
Решение с оптимизацией памяти
Вот мое оптимизированное для памяти решение в MWE:
library(data.table)
library(foreach)
dt <- data.table(chr_date_1 = c("2017-01-01", "2017-01-02", "2017-01-03"),
chr_date_2 = c("2017-01-04", "2017-01-05", "2017-01-06"))
for (date_var in c("chr_date_1", "chr_date_2")) {
dt %>%
set(j = date_var, value = ymd(.[[date_var]]))
}
Оптимизированное по скорости решение?
Поскольку есть 8,5 миллионов наблюдений и ~ 30 переменных, которыми нужно каким-то образом манипулировать, мне было интересно, можно ли оптимизировать это с точки зрения скорости с помощью foreach
. (Я запускаю R на виртуальном клиенте с 128 ГБ ОЗУ, поэтому память не является главной задачей.) Моя первая попытка выглядела так:
registerDoParallel(cores=7)
foreach (date_var = names(dt), .packages = c("data.table")) %dopar% {
set(dt, j = date_var, value = as.Date(dt[[date_var]]))
}
К сожалению, это только печатает результаты в консоли вместо обновления dt
:
[[1]]
chr_date_1 chr_date_2
1: 2017-01-01 2017-01-04
2: 2017-01-02 2017-01-05
3: 2017-01-03 2017-01-06
[[2]]
chr_date_1 chr_date_2
1: 2017-01-01 2017-01-04
2: 2017-01-02 2017-01-05
3: 2017-01-03 2017-01-06
Далее я попытался настроить .combine
и .init
,...
foreach (date_var = names(dt), .packages = c("data.table"),
.combine = "cbind", .init = dt) %dopar% {
set(dt, j = date_var, value = as.Date(dt[[date_var]]))
}
... но были добавлены новые столбцы вместо обновленных существующих:
chr_date_1 chr_date_2 chr_date_1 chr_date_2 chr_date_1 chr_date_2
1: 2017-01-01 2017-01-04 2017-01-01 2017-01-04 2017-01-01 2017-01-04
2: 2017-01-02 2017-01-05 2017-01-02 2017-01-05 2017-01-02 2017-01-05
3: 2017-01-03 2017-01-06 2017-01-03 2017-01-06 2017-01-03 2017-01-06
Итак, возможно ли вообще обновлять несколько столбцов data.table
параллельно, используя foreach
?
Если нет, может ли быть решение, в котором я создаю все новые столбцы параллельно и каким-то образом объединяю их в существующие data.table
? Один аспект, который помешал мне остановиться на этом, заключается в том, что последнее отрезанное foreach
дает то же самое (4 столбца), когда я опускаю .init = dt
.
РЕДАКТИРОВАТЬ:
Я нашел способ получить желаемый результат, но в примере с 7 переменными (= количество зарегистрированных ядер) и 3 млн наблюдений это заняло примерно в 5 раз больше времени, чем решение, оптимизированное для памяти. Так что просто для того, чтобы рассказать вам, как нельзя это делать:
result <- foreach (date_var = names(dt), .packages = c("data.table")) %dopar% {
dt[, (date_var) := lapply(.SD, as.Date, format = "%Y-%m-%d"), .SDcols = date_var]
} %>% .[[length(.)]]
Кроме того, необходимый объем памяти безумен.
lubridate
из-за удобства, но заменил его в MWE для простоты. Ваш пост заставил меня осознать тот факт, чтоymd
даже (намного!) медленнее, чемas.Date
. - person der_grund   schedule 27.09.2017DT[, (cols) := mclapply(.SD, as.Date), .SDcols=cols]
или что-то подобное. - person Frank   schedule 27.09.2017mc.cores
. Таким образом,mclapply
немного медленнее, чем решение, оптимизированное для памяти, которое я описал в своем вопросе. В любом случае, спасибо за подсказку, я попробую это дома на машине с Linux. - person der_grund   schedule 28.09.2017