不同用户的滚动计数

标签 r rolling-computation dbplyr

我想计算具有可变时间窗口的唯一用户的滚动计数。这是我所拥有的和我想要的结果的示例。

have <- data.frame(user = c(1, 2, 
                            2, 3, 
                            1, 2, 3, 
                            4, 
                            3, 4,
                            4),
                   when = lubridate::ymd("2020-01-01",
                                         "2020-01-01",
                                         "2020-01-02",
                                         "2020-01-02",
                                         "2020-01-03",
                                         "2020-01-03",
                                         "2020-01-03",
                                         "2020-01-05",
                                         "2020-01-06",
                                         "2020-01-06",
                                         "2020-01-07"))
have 
#   user       when
#1     1 2020-01-01
#2     2 2020-01-01
#3     2 2020-01-02
#4     3 2020-01-02
#5     1 2020-01-03
#6     2 2020-01-03
#7     3 2020-01-03 # note that Jan 4 is missing
#8     4 2020-01-05
#9     3 2020-01-06
#10    4 2020-01-06
#11    4 2020-01-07

want <- data.frame(when=c("2020-01-01",
                          "2020-01-02",
                          "2020-01-03",
                          "2020-01-04",
                          "2020-01-05",
                          "2020-01-06",
                          "2020-01-07"),
                   twoDayCount=c(2, # Jan 1: 1, 2
                                 3, # Jan 1-2: 1, 2, 3
                                 3, # Jan 2-3: 1, 2, 3
                                 3, # Jan 3-4: 1, 2, 3
                                 1, # Jan 4-5: 4
                                 2, # Jan 5-6: 3, 4
                                 2  # Jan 6-7: 3, 4
                                 )
                   )
want
#        when twoDayCount
#1 2020-01-01           2 # users: 1, 2
#2 2020-01-02           3 # users: 1, 2, 3
#3 2020-01-03           3 # users: 1, 2, 3
#4 2020-01-04           3 # users: 1, 2, 3
#5 2020-01-05           1 # users: 4
#6 2020-01-06           2 # users: 3, 4
#7 2020-01-07           2 # users: 3, 4

我尝试了几种方法,但他们让我计算每个窗口的所有行,而不是每个窗口的不同用户。例如,1 月 3 日所需的 2 天唯一用户数是 3(用户 1、2、3),而不是 5 行(用户 2 和 3 各出现两次)。

我的实际用例需要将滚动窗口期(在此示例中为 2 天)作为输入。

理想情况下,该解决方案适用于 {dbplyr} 可以转换为 sql 或通过可以使用 {dbplyr} 运行的 native sql 的函数。

This answer给出了如何用 sql 解决的想法:

SELECT when, count(DISTINCT user) AS dist_users 
FROM  (SELECT generate_series('2020-01-01'::date, '2020-01-07'::date, '1d')::date) AS g(when) 
LEFT   JOIN tbl t ON t.when BETWEEN g.when - 2 AND g.when 
GROUP  BY 1 
ORDER  BY 1;

最佳答案

使用 dplyrtidyr 的函数,针对 1 天窗口案例:

have %>% 
  group_by(when) %>% 
  summarise(twoDayCount = n_distinct(user))

对于较大的窗口:

window <- 2
have %>% 
  rowwise() %>% 
  mutate(when = list(when + lubridate::days(0:(window - 1)))) %>% 
  unnest(cols = when) %>%
  group_by(when) %>% 
  summarise(twoDayCount = n_distinct(user))

请注意,此方法将为您提供稍后日期(在本例中为 1 月 8 日)的行,您可能希望将其删除。

如果性能对于较大的数据集来说是一个问题,这里有一个更快(但稍微不那么优雅)的解决方案:

window <- 2
seq.Date(min(have$when), max(have$when), by = "day") %>% 
  purrr::map(function(date) {
    have %>% 
        filter(when <= date, when >= date - days(window - 1))  %>%
        summarise(userCount = n_distinct(user)) %>%
        mutate(when = date)
    }) %>% 
  bind_rows()

关于不同用户的滚动计数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63036325/

相关文章:

在 R 中按组对数据表的日期范围滚动求和

r - 如何动态构建字符串并将其传递给 R 中 dplyr 的 mutate() 函数?

r - 在 dbplyr 中传递要作为函数参数应用的函数

sql - 在 dbplyr SQL 查询中的 string::str_detect 中使用带有正则表达式的变量

r - 为什么使用assign不好?

r - 在 R 中构建相对路径的函数?

python - 如何使用先前的滚动平均值填充 pandas 数据框中的后续空值?

sql - 如何在大查询中应用 : count(distinct . ..) over (partition by ... order by)?

r - 针对 dplyr 管道中的特定列

r - 绘图和 beta 回归输出不匹配