其他data.table中查找的总和太慢了

时间:2018-04-06 06:55:24

标签: r data.table

我有一个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也很大)。

2 个答案:

答案 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

如果您有任何内存问题,请与我们联系。