Tidyverse中时间-事件数据过滤:保留至首次事件或无事件全量数据
解决时间-事件数据过滤的报错问题
你的报错根源很明确:当某个受试者没有任何事件记录时,which(event == 1)会返回空向量,而between()函数要求right参数必须是单个有效值,空向量不符合这个要求,因此触发了Expecting a single value: [extent=0]的错误。
针对你的需求——有事件的受试者保留入组到首次事件的记录,无事件的保留全部数据,这里提供两种简洁的dplyr解决方案:
方法一:先计算首次事件ID,再过滤
library(tidyverse) df %>% group_by(subject) %>% # 给每个受试者标记首次事件的ID,无事件则设为Inf(确保所有行都满足ID <= Inf) mutate(first_event_id = case_when( any(event == 1) ~ min(ID[event == 1]), TRUE ~ Inf )) %>% # 过滤到首次事件及之前的行(无事件则保留全部) filter(ID <= first_event_id) %>% # 可选:移除辅助计算列 select(-first_event_id)
代码解释:
any(event == 1):判断当前受试者是否发生过事件min(ID[event == 1]):如果有事件,取首次事件对应的最小ID(因为ID是按入组顺序生成的,最小ID就是首次事件的时间点)- 无事件时设为
Inf,这样ID <= Inf会自动保留该受试者的所有行
方法二:直接在行号层面处理(更简洁)
df %>% group_by(subject) %>% filter(row_number() <= ifelse(any(event == 1), which(event == 1)[1], n()))
代码解释:
which(event == 1)[1]:取首次事件所在的行号(因为which()返回所有事件行的索引,[1]取第一个就是首次)n():无事件时,用当前组的总行数作为边界,确保row_number() <= n()保留所有行- 这里
row_number()和你生成的ID作用完全一致,所以也可以替换成ID <= ...
验证结果
运行上述代码后,你会得到符合需求的结果:
- 受试者A:保留前3行(ID1-3,到首次事件为止)
- 受试者E:保留前2行(首次事件在ID2)
- 受试者B、D、F:保留全部行(无事件)
- 受试者C:保留前3行(首次事件在ID3)
内容的提问来源于stack exchange,提问作者user3585829
相关产品推荐
相关产品推荐

