data.table有效回收V2

时间:2019-12-05 14:26:41

标签: r data.table recycle

这是此问题的后续解答:data.table efficient recycling

这里的区别是每行的未来年份不一定相同。.

我经常在data.table中使用回收,例如当我需要对未来几年进行预测时。我每年都会重复我的原始数据。

这可能会导致类似的结果:

library(data.table)
dt <- data.table(1:500000, 500000:1, rpois(500000, 240))
dt2 <- dt[, c(.SD, .(year = 1:V3)), by = 1:nrow(dt) ]

但是我经常不得不处理数百万行,并且比这个玩具示例中的列要多得多。时间增加了..试试这个:

library(data.table)
dt <- data.table(1:5000000, 5000000:1, rpois(5000000, 240))
dt2 <- dt[, c(.SD, .(year = 1:V3)), by = 1:nrow(dt) ]

我的问题是:有没有更有效的方法来实现这一目的?

感谢您的帮助!

3 个答案:

答案 0 :(得分:4)

这是其他答案的略有改进的版本。

  • 将非默认值用于unlist
  • rep.int而不是rep
  • seq_len而不是:
  • setDT而非data.table()
  • 使用@Cole建议的sequence函数甚至更好
  • 内部vecseq的进一步细微改进

似乎总会有所作为。

时间...

library(data.table)
f0 = function(dt) {
  dt[, c(.SD, .(year = 1:V3)), by = 1:nrow(dt) ]
}
f1 = function(dt) {
  dt2 <- data.table(
    rep(dt$V1, dt$V3),
    rep(dt$V2, dt$V3),
    rep(dt$V3, dt$V3),
    unlist(lapply(dt$V3, function(x){1:x}))
  )
  dt2
}
f2 = function(dt) {
  dt2 = list(
    V1 = rep.int(dt$V1, dt$V3),
    V2 = rep.int(dt$V2, dt$V3),
    V3 = rep.int(dt$V3, dt$V3),
    year = unlist(lapply(dt$V3, seq_len), recursive=FALSE, use.names=FALSE)
  )
  setDT(dt2)
  dt2
}
f3 = function(dt) {
  ## even better with sequence function suggested by @Cole
  dt2 = list(
    V1 = rep.int(dt$V1, dt$V3),
    V2 = rep.int(dt$V2, dt$V3),
    V3 = rep.int(dt$V3, dt$V3),
    year = sequence(dt$V3)
  )
  setDT(dt2)
  dt2
}
f4 = function(dt) {
  dt[, c(lapply(.SD, rep.int, V3), year = .(sequence(V3)))]
}
f5 = function(dt) {
  dt2 = list(
    V1 = rep.int(dt$V1, dt$V3),
    V2 = rep.int(dt$V2, dt$V3),
    V3 = rep.int(dt$V3, dt$V3),
    year = data.table:::vecseq(rep.int(1L,length(dt$V3)), dt$V3, NULL)
  )
  setDT(dt2)
  dt2
}

基于“大”数据

dt <- data.table(1:5000000, 5000000:1, rpois(5000000, 240))
system.time(f0(dt))
#   user  system elapsed 
# 22.100  18.914  40.449 
system.time(f1(dt))
#   user  system elapsed 
# 35.866  15.607  51.475 
system.time(f2(dt))
#   user  system elapsed 
# 22.922   6.839  29.760 
system.time(f3(dt))
#   user  system elapsed 
#  6.509   6.723  13.233 
system.time(f4(dt))
#   user  system elapsed 
# 12.140  14.114  26.254 
system.time(f5(dt))
#   user  system elapsed 
#  6.448   4.057  10.506 

无论如何,您应该尝试改善在扩展数据集上运行的流程,因为也许您不必首先进行扩展。

例如,在frollmean函数中,有一个参数adaptive使得可以在可变长度窗口上计算滚动平均值,通常在该窗口中计算该变量首先需要扩展数据。 数据中的V3大大提醒了自适应移动平均值的窗口长度。

答案 1 :(得分:0)

这是一种更快的实现方式,但是由于lapply中的data.table循环而仍然很长

dt2 <- data.table(
  rep(dt$V1, dt$V3),
  rep(dt$V2, dt$V3),
  rep(dt$V3, dt$V3),
  unlist(lapply(dt$V3, function(x){1:x}))
)

我希望这对您有帮助!

答案 2 :(得分:0)

尝试一下:

  dt2 <- dt[dt[,rep(1:nrow(dt),V3)],]
  dt2[,year:= dt[,sequence(V3)]]