【问题标题】:R - Grouping dataframe by ID, counting number of records in beginning and ending date ranges for each IDR - 按 ID 对数据框进行分组,计算每个 ID 的开始和结束日期范围内的记录数
【发布时间】:2019-05-06 17:04:25
【问题描述】:

请注意,我已经使用 dplyr 编写了一些代码来满足我的需求,但感觉非常笨拙,我想知道是否有更优雅的解决方案

我有一个简化的数据框,本质上是这样的:

df = data.frame(
  id = c(1,1,1,2,2,2),
  date = as.Date(c('2018/01/01', '2018/01/02', 
      '2018/01/03', '2018/01/01', '2018/01/02', '2018/06/01'))
)
  id       date
1  1 2018-01-01
2  1 2018-01-02
3  1 2018-01-03
4  2 2018-01-01
5  2 2018-01-02
6  2 2018-06-01

我想要一个表格,显示每个 id 的第一条记录后 30 天内的记录数和最后一条记录后 30 天内的记录数。对于这个简单的版本,输出应该是这样的:

id  start.records   end.records
1   3               3
2   2               1

我可以用这段代码得到我想要的输出:

df %>%
  group_by(id) %>%
  summarize(min.date = min(date)) %>%
  mutate(min.date.plus.30 = min.date + 30) %>%
  fuzzy_left_join(
    df,
    by = list(x=c("id", "min.date.plus.30"), y=c("id", "date")),
    match_fun = list(`==`, `>`)
  ) %>%
  group_by(id.x, min.date) %>%
  summarize(start.records = n()) %>%
  left_join(
    df %>%
      group_by(id) %>%
      summarize(max.date = max(date)) %>%
      mutate(max.date.minus.30 = max.date - 30) %>%
      fuzzy_left_join(
        df,
        by = list(x=c("id", "max.date.minus.30"), y=c("id", "date")),
        match_fun = list(`==`, `<`)
      ) %>%
      group_by(id.x, max.date) %>%
      summarize(end.records = n()),
    by = "id.x"
  )

但这似乎是一个非常不雅的解决方案。

有没有更好的方法来做到这一点?我宁愿不使用 sqldf,因为它不能轻松处理日期计算,而且我的真实数据集有 150,000 多行,即使是简单的 sqldf 测试查询也需要永远运行。

提前感谢您的帮助!

【问题讨论】:

  • 除 sqlite 之外的任何 sqldf 后端都可以轻松处理日期。试试 H2。

标签: r dplyr


【解决方案1】:

也许我们可以使用

library(data.table)
library(lubridate)
setDT(df)[, .(start.records = sum(date <=  (first(date) + days(30))), 
       end.records = sum(date >= (last(date) - days(30)))), by = id]
#   id start.records end.records
#1:  1             3           3
#2:  2             2           1

或使用dplyr

library(dplyr)
df %>%
   group_by(id) %>%
   summarise(
       start.records = sum(date <=  (first(date) + days(30))), 
       end.records = sum(date >= (last(date) - days(30))))
# A tibble: 2 x 3
#     id start.records end.records
#  <dbl>         <int>       <int>
#1     1             3           3
#2     2             2           1

【讨论】:

  • 嘿,这很漂亮,而且感觉更像是我脑海中的 SQL 查询。猜猜我是时候阅读 data.table 了
  • 对于任何好奇的未来谷歌人来说,这种逻辑在 SQL Server 或 MySQL 中不起作用。将 MIN 或 MAX 放在 COUNT 或 SUM 中会引发错误。看起来这是一个特殊的R能力
猜你喜欢
  • 2017-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-26
  • 1970-01-01
  • 1970-01-01
  • 2020-10-08
  • 1970-01-01
相关资源
最近更新 更多