R数据表滚动唯一

时间:2018-11-19 01:22:15

标签: r data.table rolling-computation

一直在寻找一种解决方案,用于以滚动方式对数据数据表中的列的唯一值进行计数,发现rollmean但未找到类似rollunique的东西。

使用数据表实现此目标的良好做法是什么?

谢谢

1 个答案:

答案 0 :(得分:4)

1):一种选择是使用zoo::rollapply

样本数据:

library(data.table)
set.seed(0L)
sz <- 1e5L
winsz <- 5L
DT <- data.table(ID=sample(letters, sz, replace=TRUE))

使用zoo:rollapply*的样本使用情况:

DT[, numUniq := zoo::rollapplyr(ID, winsz, uniqueN, fill=NA_integer_)]

2)另一个选择是编写自己的窗口:

DT[, numUniq2 := replace(
    sapply(1:.N, function(n) uniqueN(ID[max(n-winsz+1, 1L):n])),
    .I < winsz,
    NA_integer_)]

3)另一个选择是使用data.table::shift

DT[, numUniq3 := replace(
    apply(setDT(shift(ID, 0L:(winsz-1L))), 1L, uniqueN),
    1L:.N < winsz,
    NA_integer_)]

输出:

        ID numUniq numUniq2 numUniq3
     1:  x      NA       NA       NA
     2:  g      NA       NA       NA
     3:  j      NA       NA       NA
     4:  o      NA       NA       NA
     5:  x       4        4        4
    ---                             
 99996:  k       4        4        4
 99997:  a       4        4        4
 99998:  f       4        4        4
 99999:  z       4        4        4
100000:  c       5        5        5

基准化

计时代码:

microbenchmark::microbenchmark(
    zooRoll=DT[, numUniq := zoo::rollapplyr(ID, winsz, uniqueN, fill=NA)],
    sapply=DT[, numUniq2 := replace(
        vapply(1L:.N, function(n) uniqueN(ID[max(n-winsz+1L, 1L):n]), integer(1L)),
        1L:.N < winsz,
        NA_integer_)],
    shift=DT[, numUniq3 := replace(
        apply(setDT(shift(ID, 0L:(winsz-1L))), 1L, uniqueN),
        1L:.N < winsz,
        NA_integer_)],
    times=3L)

时间:

Unit: seconds
    expr      min       lq     mean   median       uq      max neval
 zooRoll 1.723915 1.774423 1.837433 1.824931 1.894191 1.963451     3
  sapply 1.214608 1.224971 1.230763 1.235333 1.238840 1.242348     3
   shift 1.188266 1.234769 1.266852 1.281272 1.306145 1.331018     3

另请参阅: