data.table引用语义:迭代列和行组的内部

问题描述 投票:2回答:1

这个问题类似于

data.table reference semantics: memory usage of iterating through all columns

但讨论了略有不同的设置,所以我决定将它们分开。

通过将函数my_fun应用于每一列来替换data.table中的所有列,并结合使用by参数对行进行分组,在类似的设置中大致发生的情况

library(data.table)
dt <- data.table(a = 1L:10L, b = 11L:20L, c = rep(LETTERS[1:2], each = 5))
my_fun <- function(x) x + 1L

dt[, c("a", "b") := lapply(.SD, my_fun), by = "c", .SDcols = c("a", "b")]

(1)首先将问题分成几组,并对每组lapply(.SD, my_fun)进行评估。在移动到下一组之前,结果将写入dt。根据the referenced question,在这种情况下的内存开销是近似最大值(每组n_rows)x(.SD中的n_cols)x sizeof(data_type)

(2)将问题分成几组,并对每组lapply(.SD, my_fun)进行评估。完成迭代所有组后,结果将写入dt中的相应列。在这种情况下,内存开销约为(dt中的n_rows)x(.SD中的n_cols)x sizeof(data_type)

(3)以列方式逐行处理问题,对于每列,拆分列,并在当前列的每个子集上调用my_fun。完成完整列后,结果将写入dt。这将产生大约(在dt中为n_rows)x sizeof(data_type)的开销。

(4)还有别的吗?

the question referenced above的答案中,(3)可以通过类似于1级部分?datatable.optimize中概述的优化来启用,但目前(v1.11.4)不可用。

我问这个问题的原因是,特别是如果在设置(2)中,在某些情况下也可能在设置(1)中,以某种方式强制逐列方法是有意义的。

不幸的是,以下不起作用,因为set()不支持分组。

for (col in c("a", "b")) set(dt, j = col, value = my_fun(dt[[col]]), by = "c")

还有,像

lapply(c("a", "b"), function(col) dt[, (col) := my_fun(dt[[col]]), by = "c"])

不起作用,因为嵌套的子集dt[[col]]没有被分区。有没有其他方法来实现我正在尝试的,使用data.table

r data.table pass-by-reference
1个回答
0
投票

我现在认为(1)最准确地描述了如何以分组方式更新列。我从以下观察得出这个结论:如果使用by参数通过引用更新列,则新数据类型必须与旧数据类型匹配。通过引用更新整个列时不是这种情况。

为了强制逐列方法,我想可以手动执行行组子集并且有一个嵌套的双循环:一个遍历列,一个遍历行组。要确定data.table使用的组排序,我能想到的最好的就是做类似的事情

grouping <- split(
  seq_len(nrow(tbl)),
  tbl[, list(GroupIndex = rep(.GRP, .N)), by = group_by][["GroupIndex"]]
)
© www.soinside.com 2019 - 2024. All rights reserved.