R 按日期分组ID
我有一个三列的数据表id,dtstart,dtend。例如:R 按日期分组ID,r,R,我有一个三列的数据表id,dtstart,dtend。例如: id开始结束 1 01/01/2015 31/01/2015 1 02/02/2015 28/02/2015 1 01/07/2016 31/07/2016 1 01/08/2016 31/08/2016 2 01/03/2015 31/03/2015 2 01/04/2015 30/04/2015 2 01/02/2016 28/02/2016 2 01/03/2016 31/03/2
id开始结束
1 01/01/2015 31/01/2015
1 02/02/2015 28/02/2015
1 01/07/2016 31/07/2016
1 01/08/2016 31/08/2016
2 01/03/2015 31/03/2015
2 01/04/2015 30/04/2015
2 01/02/2016 28/02/2016
2 01/03/2016 31/03/2016
...
我需要创建另一个按id分组的具有相同列的数据表,但新的开始日期是原始开始日期中的最小日期,新的结束日期是原始dtend中的最大日期
当结束日期和下一个开始日期之间的间隔超过一天时,则应单独分组
例如,上述新表格为:
id start end
1 01/01/2015 28/02/2015
1 01/07/2016 31/08/2016
2 01/03/2015 30/04/2016
2 01/02/2016 31/03/2016
...
我需要for循环还是有更有效的方法(例如数据表分组)?该表超过2000万行,具有100k+唯一ID
干杯
Andrew这可以使用
dplyr
dt.new <- dt %>%
arrange(id, start, end) %>%
mutate(gr = cumsum(lag(id, default = min(id)) != id |
as.numeric(difftime(start, lag(end, default = first(start)), units = 'days')) > 1)) %>%
group_by(id, gr) %>%
summarise(start = first(start),
end = last(end))
dt.new%
排列(id、开始、结束)%>%
突变(gr=cumsum(滞后(id,默认值=min(id))!=id|
as.numeric(difftime(开始,延迟(结束,默认值=第一个(开始)),单位=‘天’)>1))%>%
分组依据(id,gr)%>%
总结(开始=第一个(开始),
结束=最后(结束))
结果是:
Source: local data frame [6 x 4]
Groups: id [?]
id gr start end
<int> <int> <dttm> <dttm>
1 1 0 2015-01-01 2015-01-31
2 1 1 2015-02-02 2015-02-28
3 1 2 2016-07-01 2016-08-31
4 2 3 2015-03-01 2015-04-30
5 2 4 2016-02-01 2016-02-28
6 2 5 2016-03-01 2016-03-31
来源:本地数据帧[6 x 4]
组:id[?]
id gr起始端
1 1 0 2015-01-01 2015-01-31
2 1 1 2015-02-02 2015-02-28
3 1 2 2016-07-01 2016-08-31
4 2 3 2015-03-01 2015-04-30
5 2 4 2016-02-01 2016-02-28
6 2 5 2016-03-01 2016-03-31
这是有效的,与您的输出不匹配,因为您请求了一天的保证金(如果您想要两天的保证金,请从>1
切换到>2
),而2016年是闰年,这在R的内部日历中。因此,2016年2月28日和2016年3月1日之间的差额为2天。再次感谢@akash87
例如,下面的第6行在一个月内,因此它仍应返回id 1从2006年2月1日到2006年9月30日的一行,但它分为两行,第一行从2006年2月1日到2006年6月12日,然后从2006年7月1日到2016年9月30日
id dtstart dtend
1 01/02/2006 28/02/2006
1 01/03/2006 31/03/2006
1 01/04/2006 30/04/2006
1 01/05/2006 31/05/2006
1 01/06/2006 30/06/2006
1 10/06/2006 12/06/2006
1 01/07/2006 31/07/2006
1 01/08/2006 31/08/2006
1 01/09/2006 30/09/2006
2 01/04/2006 30/04/2006
2 01/05/2006 31/05/2006
2 01/09/2006 30/09/2006
2 01/10/2006 31/10/2006
因此,与其返回
id start end
1 01/02/2006 30/09/2006
2 01/04/2006 31/05/2006
2 01/09/2006 31/10/2006
我们有
id start end
1 01/02/2006 12/06/2006
1 01/07/2006 30/09/2006
2 01/04/2006 31/05/2006
2 01/09/2006 31/10/2006
安德鲁我想这可能会让你走:谢谢。cumsum正在为我制作NAs。我尝试使用.numeric(as.Date(start,format=“%Y-%m-%d”)-lag(as.Date(end,format=“%Y-%m-%d”))>1),但第一个grp条目是NA,因此在分组和汇总时会包含该条目。您必须在
lag()
中添加默认值参数。我更新了我的代码。谢谢@akash87。只有一个错误,当它应该是一个时,它会分成两个。例如,如果第3行为:1 05/02/2007 05/02/2007。这一行是单独分开的。我没有得到那个错误,你能发送一个例子吗?Will do@akash87,我把它放在对原始问题的回答中,并列出了例子。这让我抓狂。啊,这带来了一个不同的问题:您正在同一列中的其他日期范围内查找日期范围。我想,一个不太优雅的原因是在新表上再次运行它,将摘要(…end=last(end))替换为摘要(…end=max(end))??我使用cumsum得到的日期范围条件(lag(id,default=min(id))!=id |!(dtstart%in%min(dtstart):max(dtend)),但是添加difftime子句会覆盖它。