R:按ID和指定数据聚合历史记录
我以前也问过类似的问题,得到了很大的帮助: 不同的是,对于前一篇文章,我对汇总所有历史信息感兴趣,但现在我希望只指定90天以前的内容 以下是我的数据的外观示例:R:按ID和指定数据聚合历史记录,r,data.table,dplyr,R,Data.table,Dplyr,我以前也问过类似的问题,得到了很大的帮助: 不同的是,对于前一篇文章,我对汇总所有历史信息感兴趣,但现在我希望只指定90天以前的内容 以下是我的数据的外观示例: strDates <- c("09/09/16", "5/7/16", "5/6/16", "2/13/16", "2/11/16","1/7/16", "11/8/16","6/8/16", "5/8/16","2/13/16","1/3/16", "1/1/16") Date<-as.Date(str
strDates <- c("09/09/16", "5/7/16", "5/6/16", "2/13/16", "2/11/16","1/7/16",
"11/8/16","6/8/16", "5/8/16","2/13/16","1/3/16", "1/1/16")
Date<-as.Date(strDates, "%m/%d/%y")
ID <- c("A", "A", "A", "A","A", "A", "B","B","B","B","B", "B")
Event <- c(1,0,1,0,1,1, 0,1,1,1,0, 1)
sample_df <- data.frame(Date,ID,Event)
strDates一个部分矢量化的dplyr
解决方案,您可以在其中组合do
(在组中循环)和行操作(这样您可以将日期引用为每行的日期,$Date
作为每个组中的整个Date
列):
sample_df%>%
分组依据(ID)%>%
do(按行(%)%%>%
变异(PrevEnc90D=sum(日期-.$Date<90和日期-.$Date>0),
PrevEvent90D=总和(.$Event[日期-.$Date<90和日期-.$Date>0]))
#来源:本地数据帧[12 x 5]
#组别:ID[2]
#日期ID事件PrevEnc90D Prevent90d
#
#1 2016-09-09 A 10 0 0
#2 2016-05-07 A 0 3 2
#3 2016-05-06 A 12 1
#4 2016-02-13 A 0 2 2
#5 2016-02-11a
#6 2016-01-07 A 10 0 0
#7 2016-11-08乙00
#8 2016-06-08 B1
#9 2016-05-08 B1
#10 2016-02-13 B 1 2 1
#11 2016-01-03 B 0 1 1
#12 2016-01-01 B 1 0 0 0
这里有一个替代的数据表
解决方案,应该非常有效。这利用了v1.10.0中引入的新的非等联接,并结合了by=.EACHI
,允许您在联接时对每个联接进行计算
library(data.table)#v1.10.0
setDT(sample_df)[,Date2:=Date-90]#设置范围(可能在将来可以避免)
sample_-df[sample_-df,#二进制与自身连接
(Enc90D=0.N,Ev90D=sum(Event,na.rm=TRUE)),进行计算
on=(ID=ID,日期<日期,日期>日期2),#加入
by=.EACHI]#对每一场比赛进行计算
#ID日期Enc90D Ev90D
#1:A 2016-09-09 2016-06-11 0
#2:A 2016-05-07 2016-02-07 3 2
#3:A 2016-05-06 2016-02-06 2 1
#4:A 2016-02-13 2015-11-15 2
#5:A 2016-02-11 2015-11-13 1
#6:A 2016-01-07 2015-10-09
#7:B 2016-11-08 2016-08-10 0
#8:B 2016-06-08 2016-03-10 11
#9:B 2016-05-08 2016-02-08 1
#10:B 2016-02-13 2015-11-15 2 1
#11:B 2016-01-03 2015-10-05 11
#12:B 2016-01-01 2015-10-03 0
一个相当冗长的dplyr解决方案,它使用的行比实际需要的多。其思想是为每个日期创建一个完全联接的表,然后使用窗口函数。如果需要不同的窗口计算,这可能很有用
library(dplyr)
dates <- data.frame(Date = seq(from = -90 + min(sample_df$Date), to = max(sample_df$Date), by=1))
extended_df <- data.frame(ID = unique(sample_df$ID)) %>%
merge(dates) %>%
left_join(sample_df, by=(c("ID", "Date"))) %>%
arrange(ID, desc(Date)) %>%
mutate(Encounter = as.integer(!is.na(Event)),
Event = ifelse(is.na(Event), 0, Event)) %>%
group_by(ID) %>%
mutate(PrevEnc90D = rollsum(lead(Encounter), k=90, fill=0, align="left"),
PrevEvent90D = rollsum(lead(Event), k=90, fill=0, align="left")) %>%
inner_join(sample_df[,c("ID", "Date")]) %>%
arrange(ID, desc(Date))
extended_df
库(dplyr)
日期%
左连接(示例df,by=(c(“ID”,“Date”))%>%
安排(ID,描述(日期))%>%
mutate(遭遇=as.integer(!is.na(事件)),
Event=ifelse(is.na(事件),0,事件))%>%
分组依据(ID)%>%
变异(PrevEnc90D=rollsum(引导(遭遇),k=90,fill=0,align=“left”),
PrevEvent90D=rollsum(lead(事件),k=90,fill=0,align=“left”)%%>%
内部联接(样本df[,c(“ID”,“日期”))%>%
安排(ID、描述(日期))
扩展的
来源:本地数据帧[12 x 6]
组别:ID[2]
ID Date Event Encounter PrevEnc90D PrevEvent90D
<fctr> <date> <dbl> <int> <dbl> <dbl>
1 A 2016-09-09 1 1 0 0
2 A 2016-05-07 0 1 3 2
3 A 2016-05-06 1 1 2 1
4 A 2016-02-13 0 1 2 2
5 A 2016-02-11 1 1 1 1
6 A 2016-01-07 1 1 0 0
7 B 2016-11-08 0 1 0 0
8 B 2016-06-08 1 1 1 1
9 B 2016-05-08 1 1 1 1
10 B 2016-02-13 1 1 2 1
11 B 2016-01-03 0 1 1 1
12 B 2016-01-01 1 1 0 0
ID日期事件遭遇PrevEnc90D prevent90d
1A 2016-09-09 110 0 0
2A 2016-05-07 01 3 2
3A 2016-05-06 11
4a 2016-02-13 01 2
5A 2016-02-11 1
6 A 2016-01-07 11 0 0
7 B 2016-11-08 01 0 0
8 B 2016-06-08 1
9 B 2016-05-08 1
10B 2016-02-13 11
11B 2016-01-03 01
12 B 2016-01-01 11 0 0
以及另一种尽可能避免重复求和和和关系运算的方法:
do.call(rbind,
lapply(split(sample_df, sample_df$ID),
function(x) {
i = nrow(x) - findInterval(x$Date - 90, rev(x$Date))
cs = cumsum(x$Event)
cbind(x, PrevEnc90D = i - (1:nrow(x)), PrevEvent90D = cs[i] - cs)
}))
# Date ID Event PrevEnc90D PrevEvent90D
#A.1 2016-09-09 A 1 0 0
#A.2 2016-05-07 A 0 3 2
#A.3 2016-05-06 A 1 2 1
#A.4 2016-02-13 A 0 2 2
#A.5 2016-02-11 A 1 1 1
#A.6 2016-01-07 A 1 0 0
#B.7 2016-11-08 B 0 0 0
#B.8 2016-06-08 B 1 1 1
#B.9 2016-05-08 B 1 1 1
#B.10 2016-02-13 B 1 2 1
#B.11 2016-01-03 B 0 1 1
#B.12 2016-01-01 B 1 0 0
上面假设“日期”在每个“ID”中按递减顺序排列(如果不是这样的话,这非常简单)。这里的主要思想是:(i)为每个日期确定前90天的位置,(ii)计算一次预先累积的总和,(iii)减去相应的指数/cumsum
s以获得输出。我在这里使用了split
/lappy
路线,以“ID”进行分组,但我想,它很容易转移到任何更好的工具上。我很欣赏这个解决方案,并将很快试用它!我应该补充一点,我有一个非常小的数据集(
ID Date Event Encounter PrevEnc90D PrevEvent90D
<fctr> <date> <dbl> <int> <dbl> <dbl>
1 A 2016-09-09 1 1 0 0
2 A 2016-05-07 0 1 3 2
3 A 2016-05-06 1 1 2 1
4 A 2016-02-13 0 1 2 2
5 A 2016-02-11 1 1 1 1
6 A 2016-01-07 1 1 0 0
7 B 2016-11-08 0 1 0 0
8 B 2016-06-08 1 1 1 1
9 B 2016-05-08 1 1 1 1
10 B 2016-02-13 1 1 2 1
11 B 2016-01-03 0 1 1 1
12 B 2016-01-01 1 1 0 0
do.call(rbind,
lapply(split(sample_df, sample_df$ID),
function(x) {
i = nrow(x) - findInterval(x$Date - 90, rev(x$Date))
cs = cumsum(x$Event)
cbind(x, PrevEnc90D = i - (1:nrow(x)), PrevEvent90D = cs[i] - cs)
}))
# Date ID Event PrevEnc90D PrevEvent90D
#A.1 2016-09-09 A 1 0 0
#A.2 2016-05-07 A 0 3 2
#A.3 2016-05-06 A 1 2 1
#A.4 2016-02-13 A 0 2 2
#A.5 2016-02-11 A 1 1 1
#A.6 2016-01-07 A 1 0 0
#B.7 2016-11-08 B 0 0 0
#B.8 2016-06-08 B 1 1 1
#B.9 2016-05-08 B 1 1 1
#B.10 2016-02-13 B 1 2 1
#B.11 2016-01-03 B 0 1 1
#B.12 2016-01-01 B 1 0 0