一直在寻找一种解决方案,用于以滚动方式对数据数据表中的列的唯一值进行计数,发现rollmean但未找到类似rollunique的东西。
使用数据表实现此目标的良好做法是什么?
谢谢
答案 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
另请参阅: