数据表中大面板按行操作的性能问题
Performance issues with large panel row-wise operation in datatable
这是一个后续问题。我有以下面板数据:
library(data.table)
set.seed(1)
time=rep(seq(as.Date("2001-01-31"), as.Date("2050-01-31"), by="years"))
nrOfIDs <- 10000
groupvars <- letters[1:5]
DT <- data.table(time=rep(time,nrOfIDs),
ind=rep(1:nrOfIDs,each=length(time)),
x=sample(nrOfIDs*length(time)),
y=sample(nrOfIDs*length(time)),
group=rep(groupvars,each=(nrOfIDs*length(time))/length(groupvars)))
nrow(DT) # 500000
简而言之,我想要做的是,对于每个 ID,获取“x”列中的每个值,并将“y”列中的所有现有值添加到它。这必须在每个“组”的数据集中单独完成。
例如,对于 x1,我需要计算 x1 + y1、x1 + y2、x1 + y3 等等。然后对 x2、x3、x4 等相同。在每种情况下,始终将所有可能的 y 值添加到相应的 x 值。
我收到了几个关于如何执行此操作的答案(请参阅:),但它们不适用于我的数据集。问题是它爆炸了。举例来说,在上面的代码中,我使用了nrOfIDs <- 10000
。这可以进一步增加以更接近我的实际问题,但代码已经不适用于这个数字。例如,使用带有以下代码的交叉连接:
DT[, CJ(x, y, sorted = FALSE), by = .(ind,group)]
给出:Error in [.data.table(DT, , CJ(x, y, sorted = FALSE), by = .(time, group)) : negative length vectors are not allowed
原因是结果行太多。例如,如果我们使用:
DT[, CJ(x, y, sorted = FALSE), by = .(group)]
我们得到:Error in CJ(x, y, sorted = FALSE) : Cross product of elements provided to CJ() would result in 10000000000 rows which exceeds .Machine$integer.max == 2147483647
所以这似乎是一个性能问题,但不仅如此。
最后我只是在寻找每个结果对的最低总和。假设 x1 与 y1 的总和为 2,x1 与 y2 的总和为 3,等等,所有其他总和 > 2。因此在这种情况下我只需要保存 x1 与 y1 的总和。但要实现这一点,我们也需要中间结果。所以我不确定如何在不使数据集变大的情况下做到这一点。
我会提供任何提示。我不确定,但在我看来,对于更大的数据集,这只能通过循环 ID 来解决?
这里可能遗漏了什么,但是...
f <- \(x, y) {sapply(as.data.table(outer(y,x,'+')), min)}
DT[, .(result = f(x, y)), by=.(group, ind)]
## group ind result
## 1: a 1 24664
## 2: a 1 453013
## 3: a 1 124689
## 4: a 1 436799
## 5: a 1 332006
这在我的机器上运行 3.9 秒。
这是一个后续问题。我有以下面板数据:
library(data.table)
set.seed(1)
time=rep(seq(as.Date("2001-01-31"), as.Date("2050-01-31"), by="years"))
nrOfIDs <- 10000
groupvars <- letters[1:5]
DT <- data.table(time=rep(time,nrOfIDs),
ind=rep(1:nrOfIDs,each=length(time)),
x=sample(nrOfIDs*length(time)),
y=sample(nrOfIDs*length(time)),
group=rep(groupvars,each=(nrOfIDs*length(time))/length(groupvars)))
nrow(DT) # 500000
简而言之,我想要做的是,对于每个 ID,获取“x”列中的每个值,并将“y”列中的所有现有值添加到它。这必须在每个“组”的数据集中单独完成。 例如,对于 x1,我需要计算 x1 + y1、x1 + y2、x1 + y3 等等。然后对 x2、x3、x4 等相同。在每种情况下,始终将所有可能的 y 值添加到相应的 x 值。
我收到了几个关于如何执行此操作的答案(请参阅:nrOfIDs <- 10000
。这可以进一步增加以更接近我的实际问题,但代码已经不适用于这个数字。例如,使用带有以下代码的交叉连接:
DT[, CJ(x, y, sorted = FALSE), by = .(ind,group)]
给出:Error in [.data.table(DT, , CJ(x, y, sorted = FALSE), by = .(time, group)) : negative length vectors are not allowed
原因是结果行太多。例如,如果我们使用:
DT[, CJ(x, y, sorted = FALSE), by = .(group)]
我们得到:Error in CJ(x, y, sorted = FALSE) : Cross product of elements provided to CJ() would result in 10000000000 rows which exceeds .Machine$integer.max == 2147483647
所以这似乎是一个性能问题,但不仅如此。
最后我只是在寻找每个结果对的最低总和。假设 x1 与 y1 的总和为 2,x1 与 y2 的总和为 3,等等,所有其他总和 > 2。因此在这种情况下我只需要保存 x1 与 y1 的总和。但要实现这一点,我们也需要中间结果。所以我不确定如何在不使数据集变大的情况下做到这一点。
我会提供任何提示。我不确定,但在我看来,对于更大的数据集,这只能通过循环 ID 来解决?
这里可能遗漏了什么,但是...
f <- \(x, y) {sapply(as.data.table(outer(y,x,'+')), min)}
DT[, .(result = f(x, y)), by=.(group, ind)]
## group ind result
## 1: a 1 24664
## 2: a 1 453013
## 3: a 1 124689
## 4: a 1 436799
## 5: a 1 332006
这在我的机器上运行 3.9 秒。