选择R中每个ID每个日期的第一个正匹配项
我有一个数据框架,随着时间的推移,观察结果会有所不同。只要一个ID的“匹配”值为正值,就必须删除后面日期中具有该ID的行。这是一个示例数据帧:选择R中每个ID每个日期的第一个正匹配项,r,R,我有一个数据框架,随着时间的推移,观察结果会有所不同。只要一个ID的“匹配”值为正值,就必须删除后面日期中具有该ID的行。这是一个示例数据帧: Date ID Match 2018-06-06 5 1 2018-06-06 6 0 2018-06-07 5 1 2018-06-07 6 0 2018-06-07 7 1 2018-06-08 5 0 2018-06-08 6 1 2018-06-08 7 1 2018
Date ID Match
2018-06-06 5 1
2018-06-06 6 0
2018-06-07 5 1
2018-06-07 6 0
2018-06-07 7 1
2018-06-08 5 0
2018-06-08 6 1
2018-06-08 7 1
2018-06-08 8 1
期望输出:
Date ID Match
2018-06-06 5 1
2018-06-06 6 0
2018-06-07 6 0
2018-06-07 7 1
2018-06-08 6 1
2018-06-08 8 1
换言之,由于ID=5在2018-06-06具有正匹配,因此ID=5的行将在接下来的几天中删除,但保留该ID第一个正匹配的行
可复制示例:
Date <- c("2018-06-06","2018-06-06","2018-06-07","2018-06-07","2018-06-07","2018-06-08","2018-06-08","2018-06-08","2018-06-08")
ID <- c(5,6,5,6,7,5,6,7,8)
Match <- c(1,0,1,0,1,0,1,1,1)
df <- data.frame(Date,ID,Match)
日期单向:
library(data.table)
setDT(df)
df[, Match := as.integer(as.character(Match))] # fix bad format
df[, .SD[shift(cumsum(Match), fill=0) == 0], by=ID]
ID Date Match
1: 5 2018-06-06 1
2: 6 2018-06-06 0
3: 6 2018-06-07 0
4: 6 2018-06-08 1
5: 7 2018-06-07 1
6: 8 2018-06-08 1
我们希望在第一个匹配==1之后删除行
cumsum
获取匹配的累积和。在第一个匹配==1之前,它一直为零。我们希望保留后一行,因此在前一行中使用受@Frank answer启发的shift
检查cumsum
library(dplyr)
df %>% group_by(ID) %>% mutate(Flag = cumsum(as.numeric(Match))) %>%
filter(Match==0 & Flag==0 | Match==1 & Flag==1)
# A tibble: 6 x 4
# Groups: ID [4]
Date ID Match Flag
<chr> <chr> <chr> <dbl>
1 2018-06-06 5 1 1
2 2018-06-06 6 0 0
3 2018-06-07 6 0 0
4 2018-06-07 7 1 1
5 2018-06-08 6 1 1
6 2018-06-08 8 1 1
库(dplyr)
df%%>%group_by(ID)%%>%mutate(Flag=cumsum(as.numeric(Match)))%%
过滤器(匹配==0&Flag==0 |匹配==1&Flag==1)
#一个tibble:6x4
#组别:ID[4]
日期ID匹配标志
1 2018-06-06 5 1 1
2 2018-06-06 6 0 0
3 2018-06-07 6 0 0
4 2018-06-07 7 1 1
5 2018-06-08 6 1 1
6 2018-06-08 8 1 1
资料
Date这里有一种替代方法,我们发现每个ID
的Match
=1(即第一行为正匹配)的最小行数,并根据此进行过滤:
Date <- c("2018-06-06","2018-06-06","2018-06-07","2018-06-07","2018-06-07","2018-06-08","2018-06-08","2018-06-08","2018-06-08")
ID <- c(5,6,5,6,7,5,6,7,8)
Match <- c(1,0,1,0,1,0,1,1,1)
df <- as.data.frame(cbind(Date,ID,Match))
library(dplyr)
df %>%
group_by(ID) %>% # for each ID
mutate(min_row = min(row_number()[Match == 1])) %>% # get the first row where you have 1
filter(row_number() <= min_row) %>% # keep previous rows and that row
ungroup() %>% # forget the grouping
select(-min_row) # remove unnecessary column
# # A tibble: 6 x 3
# Date ID Match
# <fct> <fct> <fct>
# 1 2018-06-06 5 1
# 2 2018-06-06 6 0
# 3 2018-06-07 6 0
# 4 2018-06-07 7 1
# 5 2018-06-08 6 1
# 6 2018-06-08 8 1
下面是另一个dplyr
选项:
library(dplyr)
df %>%
mutate(Date = as.Date(Date)) %>%
group_by(ID) %>%
mutate(first_match = min(Date[Match == 1])) %>%
filter((Match == 1 & Date == first_match) | (Match == 0 & Date < first_match)) %>%
ungroup() %>%
select(-first_match)
# A tibble: 6 x 3
Date ID Match
<date> <fct> <fct>
1 2018-06-06 5 1
2 2018-06-06 6 0
3 2018-06-07 6 0
4 2018-06-07 7 1
5 2018-06-08 6 1
6 2018-06-08 8 1
库(dplyr)
df%>%
变异(日期=as.Date(日期))%>%
分组依据(ID)%>%
变异(第一次匹配=min(日期[匹配=1]))%>%
筛选器((匹配==1和日期==第一次匹配)|(匹配==0和日期<第一次匹配))%>%
解组()%>%
选择(-first_match)
#一个tibble:6x3
日期ID匹配
1 2018-06-06 5 1
2 2018-06-06 6 0
3 2018-06-07 6 0
4 2018-06-07 7 1
5 2018-06-08 6 1
6 2018-06-08 8 1
我有另一种方法可以使用dplyr
library(dplyr)
df %>%
group_by(ID) %>%
# You can use order(Date) if you don't want to coerce Date into date object
mutate(ord = order(Date), first_match = min(ord[Match > 0]), ind = seq_along(Date)) %>%
filter(ind <= first_match) %>%
select(Date:Match)
# A tibble: 6 x 3
# Groups: ID [4]
Date ID Match
<chr> <dbl> <dbl>
1 2018-06-06 5 1
2 2018-06-06 6 0
3 2018-06-07 6 0
4 2018-06-07 7 1
5 2018-06-08 6 1
6 2018-06-08 8 1
库(dplyr)
df%>%
分组依据(ID)%>%
#如果不想将日期强制转换为日期对象,可以使用order(Date)
变异(ord=订单(日期),首次匹配=最小(ord[匹配>0]),ind=顺序(日期))%>%
过滤器(ind%
选择(日期:匹配)
#一个tibble:6x3
#组别:ID[4]
日期ID匹配
1 2018-06-06 5 1
2 2018-06-06 6 0
3 2018-06-07 6 0
4 2018-06-07 7 1
5 2018-06-08 6 1
6 2018-06-08 8 1
如果特定ID的第一个1后面跟着该特定ID的0,则此操作将中断。@AntoniosK您是正确的,请您现在检查它。是的,现在它可以工作了(即解决我提到的问题)。仅供参考,您不需要cbind
。只需执行data.frame(日期、ID、匹配)
。使用cbind
,将生成一个矩阵,因此所有三列都将成为因子或字符串。
library(dplyr)
df %>%
mutate(Date = as.Date(Date)) %>%
group_by(ID) %>%
mutate(first_match = min(Date[Match == 1])) %>%
filter((Match == 1 & Date == first_match) | (Match == 0 & Date < first_match)) %>%
ungroup() %>%
select(-first_match)
# A tibble: 6 x 3
Date ID Match
<date> <fct> <fct>
1 2018-06-06 5 1
2 2018-06-06 6 0
3 2018-06-07 6 0
4 2018-06-07 7 1
5 2018-06-08 6 1
6 2018-06-08 8 1
library(dplyr)
df %>%
group_by(ID) %>%
# You can use order(Date) if you don't want to coerce Date into date object
mutate(ord = order(Date), first_match = min(ord[Match > 0]), ind = seq_along(Date)) %>%
filter(ind <= first_match) %>%
select(Date:Match)
# A tibble: 6 x 3
# Groups: ID [4]
Date ID Match
<chr> <dbl> <dbl>
1 2018-06-06 5 1
2 2018-06-06 6 0
3 2018-06-07 6 0
4 2018-06-07 7 1
5 2018-06-08 6 1
6 2018-06-08 8 1