r - 如何按组有条件地计算唯一值
问题描述
我有一个每日用户记录。每天一个用户可以有多个记录。我想计算滚动 3 天窗口中的唯一用户数。我怎样才能做到这一点?
set.seed(123)
dat<-data.table(day=rep(1:5,sample(6,5)))
dat$id<-sample(10,dat[,.N],replace=T)
> dat
day id
1: 1 1
2: 1 6
3: 2 9
4: 2 6
5: 2 5
6: 2 10
7: 3 5
8: 3 7
9: 3 6
10: 3 2
11: 3 9
12: 3 3
13: 4 1
14: 4 4
15: 4 10
16: 5 9
17: 5 7
18: 5 7
19: 5 10
20: 5 7
我希望结果如下,即对于每一天 x,我想计算第 x、x-1 和 x-2 天的唯一 ID 数。
sqldf('select a.day,count(distinct b.id) as user_cnt
from dat as a left join dat as b on a.day<=b.day+2 and a.day>=b.day group by a.day')
day user_cnt
1 2
2 5
3 8
4 9
5 9
解决方案
通过多次阅读您的问题并检查您想要的输出,您似乎想要一个自适应滚动“独特”功能,向右对齐(即前n 天),窗口为 3 天。
应该可以使用数据表,并且akrun提供了一个非自适应解决方案,其中 align='left'。但是,您需要 align='right' (默认值)。
library(data.table)
dt[, .(.(id)), day][
, frollapply(seq_len(.N), n = 3, FUN = function(i) uniqueN(unlist(V1[i])))
[1] NA NA 8 9 9
注意
dt[, .(.(id)), day]
day V1
1: 1 1,6
2: 2 9, 6, 5,10
3: 3 5,7,6,2,9,3
4: 4 1, 4,10
5: 5 9, 7, 7,10, 7
frollapply
不幸的是,与其他(frollmean
和)不同,data.table 没有为函数提供部分(自适应=真)窗口选项frollsum
。
我们能试试...
nk <- function(x, k) c(seq.int(k), rep(k, x - k))
dt[, .(.(id)), day][
, frollapply(seq_len(.N), n = nk(.N, 3), FUN = function(i) uniqueN(unlist(V1[i])))
V1 V2 V3 V4 V5
1: 2 NA NA NA NA
2: 4 5 NA NA NA
3: 6 7 8 8 8
4: 3 9 9 9 9
5: 3 5 9 9 9
但是我们得到了一个包含 5 列的 data.table,其中的答案隐藏在对角线中。
所以我最终使用mapply
了一个用户定义的函数N_unique
来计算滚动窗口返回的 id 列表中的唯一值。我们仍然可以通过nk
上面定义的函数使用部分窗口宽度。
N_unique <- function(i, width, x){
uniqueN(unlist(x[(i - (width - 1)):i]))
}
dt2 <- dt[, .(.(id)), day][
, user_cnt := mapply(FUN = N_unique, i = seq_len(.N),
width = nk(.N, 3), MoreArgs = list(x = V1))][, V1:=NULL]
dt2
day user_cnt
1: 1 2
2: 2 5
3: 3 8
4: 4 9
5: 5 9
资料:
dput(dt)
structure(list(day = c(1L, 1L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L,
3L, 3L, 4L, 4L, 4L, 5L, 5L, 5L, 5L, 5L), id = c(1, 6, 9, 6, 5,
10, 5, 7, 6, 2, 9, 3, 1, 4, 10, 9, 7, 7, 10, 7)), row.names = c(NA,
-20L), class = c("data.table", "data.frame"), .internal.selfref = <pointer: 0x0bae2498>)
注意dt
:使用创建的命令set.seed
导致与 OP 提供的不同。
推荐阅读
- javascript - 从键名中获取数组的元素对象
- c# - 如何为另一个应用程序捕获 WM_MINIMIZE?
- varnish-vcl - 使用 Fastly CDN 将动态 CSS URL 放入 HTTP 标头
- scala - 如何在我们有 null 的日期字段中放置一些默认值,例如“9999-12-31”
- java - Java 8 中的多个空值检查
- reactjs - 为什么“从'react'导入{React};” 不行?
- javascript - 如何解决:ReferenceError:未定义 WebAssembly
- import - 大型 csv 文件导入 phpmyadmin - 再次 - 其他答案不起作用
- node.js - NodeJs Mongoose findById 返回空文档,状态为 true
- angular - Angular 6 上的分页