Как обновить `data.table` в `foreach` по ссылке

Я прочитал большой файл .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(.)]]

Кроме того, необходимый объем памяти безумен.


person der_grund    schedule 27.09.2017    source источник
comment
Нет, это невозможно. Однако в зависимости от вашего формата даты в пакетах доступны более быстрые парсеры даты.   -  person Roland    schedule 27.09.2017
comment
stackoverflow.com/questions/35247063 /   -  person Roland    schedule 27.09.2017
comment
Спасибо, что указали на это, @Roland. На самом деле я использовал lubridate из-за удобства, но заменил его в MWE для простоты. Ваш пост заставил меня осознать тот факт, что ymd даже (намного!) медленнее, чем as.Date.   -  person der_grund    schedule 27.09.2017
comment
Вы просто распараллеливаете по столбцам? Я предполагаю, что есть DT[, (cols) := mclapply(.SD, as.Date), .SDcols=cols] или что-то подобное.   -  person Frank    schedule 27.09.2017
comment
К сожалению, я запускаю R в Windows на работе, поэтому не могу увеличить mc.cores. Таким образом, mclapply немного медленнее, чем решение, оптимизированное для памяти, которое я описал в своем вопросе. В любом случае, спасибо за подсказку, я попробую это дома на машине с Linux.   -  person der_grund    schedule 28.09.2017