R—按ID对数据帧进行分组,计算每个ID的开始日期和结束日期范围内的记录数

R—按ID对数据帧进行分组,计算每个ID的开始日期和结束日期范围内的记录数,r,dplyr,R,Dplyr,请注意,我已经使用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在第一条记

请注意,我已经使用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在第一条记录的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"
  )
df%>%
分组依据(id)%>%
汇总(最小日期=最小日期))%>%
突变(min.date.plus.30=min.date+30)%>%
模糊左联合(
df,
by=list(x=c(“id”,“min.date.plus.30”),y=c(“id”,“date”),
匹配乐趣=列表(`=`,`>`)
) %>%
分组依据(id.x,最小日期)%>%
汇总(start.records=n())%>%
左联合(
df%>%
分组依据(id)%>%
汇总(最长日期=最长日期))%>%
变异(最大日期-30=最大日期-30)%>%
模糊左联合(
df,
by=list(x=c(“id”,“max.date.减0.30”),y=c(“id”,“date”),
匹配乐趣=列表(`=`,`%
分组依据(id.x,最长日期)%>%
汇总(end.records=n()),
by=“id.x”
)
但这似乎是一个非常不雅观的解决方案

有更好的方法吗?我不想使用sqldf,因为它不容易处理日期计算,而且我的真实数据集有150000多行,即使是简单的sqldf测试查询也需要永远运行

提前感谢您的帮助!

也许我们可以使用

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

嘿,这很巧妙,而且感觉更像我脑海中的SQL查询。我想现在是我阅读数据的时候了。表对于任何好奇的未来谷歌用户来说,这种逻辑在SQL Server或MySQL中不起作用。将最小值或最大值放在COUNT或SUM中会抛出一个错误。看起来这是sqldf后端的一种特殊能力比sqlite更容易处理日期。试试H2。
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
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