我有一个data.table with data(DT.B),并且必须根据DT.A求值。这是一个MWE,但由于实际数据的行数超过20M,因此需要更快。带有新列的DT.A是理想的结果。
library(data.table)
set.seed(46)
rows.DT <- 100 # In reality 20E6
DT.A <- data.table(Cat.A=1:rows.DT,
Cat.B.1=sample(1:100, rows.DT, replace=TRUE),
Cat.B.2=sample(1:100, rows.DT, replace=TRUE))
DT.B.1 <- data.table(Cat.B=1:100, data.1=sample(1:10, 100, replace=TRUE), data.2=sample(1:10, 100, replace=TRUE), data.3=sample(1:10, 100, replace=TRUE))
DT.B.2 <- data.table(Cat.B=1:100, data.1=sample(1:10, 100, replace=TRUE), data.2=sample(1:10, 100, replace=TRUE), data.3=sample(1:10, 100, replace=TRUE))
DT.B <- rbind(DT.B.1, DT.B.2); rm(DT.B.1, DT.B.2)
DT.A[, c("sums.1", "sums.2", "sums.3"):=0]
i <- 1
for (i in 1:nrow(DT.A)) {
DT.A[i, sums.1:=sum(DT.B[Cat.B==Cat.B.1, data.1], DT.B[Cat.B==Cat.B.2, data.1])]
DT.A[i, sums.2:=sum(DT.B[Cat.B==Cat.B.1, data.2], DT.B[Cat.B==Cat.B.2, data.2])]
DT.A[i, sums.3:=sum(DT.B[Cat.B==Cat.B.1, data.3], DT.B[Cat.B==Cat.B.2, data.3])]
}
我试过的其他方法失败了,因为计算机耗尽了RAM(64GB ......),所以这也是对解决方案的限制(DT.B也很大)。
答案 0 :(得分:2)
可能的替代解决方案:
nms1 <- paste0('data.',1:3)
nms2 <- paste0('sums.',1:3)
DT.A.long <- melt(DT.A, id = 1, value.name = 'Cat.B')
DT.A.long[DT.B[, lapply(.SD, sum, na.rm = TRUE), by = Cat.B]
, on = .(Cat.B)
, (nms2) := mget(paste0('i.',nms1))
][, (nms2) := lapply(.SD, sum, na.rm = TRUE), by = Cat.A, .SDcols = nms2
][, dcast(.SD, ... ~ variable, value.var = 'Cat.B')]
答案 1 :(得分:1)
在执行总和之前,您可以考虑将DT.A与DT.B.1和DT.B.2连接以获得广泛的data.table。
library(data.table)
set.seed(46L)
rows.DT <- 20e6 # In reality 20E6
DT.A <- data.table(Cat.A=1:rows.DT,
Cat.B.1=sample(1:100, rows.DT, replace=TRUE),
Cat.B.2=sample(1:100, rows.DT, replace=TRUE))
DT.B.1 <- data.table(Cat.B=1:100, data.1=sample(1:10, 100, replace=TRUE), data.2=sample(1:10, 100, replace=TRUE), data.3=sample(1:10, 100, replace=TRUE))
DT.B.2 <- data.table(Cat.B=1:100, data.1=sample(1:10, 100, replace=TRUE), data.2=sample(1:10, 100, replace=TRUE), data.3=sample(1:10, 100, replace=TRUE))
DT.B <- rbind(DT.B.1, DT.B.2); rm(DT.B.1, DT.B.2)
#using @jaap's insight
DT.B <- DT.B[, lapply(.SD, sum, na.rm = TRUE), by=Cat.B]
#join with DT.B using Cat.B.1 first and aggregate to reduce dimensions
dt1 <- DT.B[DT.A, on=c("Cat.B"="Cat.B.1")][,
.SD[, lapply(.SD, sum), by=.(Cat.A, Cat.B, Cat.B.2)]]
setnames(dt1, "Cat.B", "Cat.B.1")
#repeat for Cat.B.2
dt2 <- DT.B[DT.A, on=c("Cat.B"="Cat.B.2")][,
.SD[, lapply(.SD, sum), by=.(Cat.A, Cat.B.1, Cat.B)]]
setnames(dt2, "Cat.B", "Cat.B.2")
#merge both and sum
res <- dt1[dt2, on=.(Cat.A, Cat.B.1, Cat.B.2)][,
':=' (
sums.1 = data.1 + i.data.1,
sums.2 = data.2 + i.data.2,
sums.3 = data.3 + i.data.3
)]
res
如果您有任何内存问题,请与我们联系。