我使用.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]]))
}
由于有850万个观测值和~30个应该以某种方式操纵的变量,我想知道这是否可以使用foreach
在速度方面进行优化。 (我在具有128GB RAM的虚拟客户端上运行R,因此内存不是主要问题。)我的第一次尝试看起来像这样:
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
时,最后.init = dt
剪切产生相同的( 4列)。
我找到了获得所需结果的方法,但在一个包含7个变量(=已注册核心数)和3M观察值的示例中,这比内存优化解决方案长约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(.)]]
此外,所需的内存量是疯狂的。