如何筛选处于多个治疗时间区间内的评分数据(R语言)
问题描述
需要从数据框中筛选出**评分时间(score_time)**处于对应ID的任意治疗时间区间内的评分记录。每个ID包含多条带测量时间的评分数据,以及多条治疗开始(treatment_start)和结束(treatment_end)时间记录。
数据结构如下:
structure(list(ID = c("A", "A", "A", "A", "A", "B", "B", "B", "B", "B"), score_time = c("2022/09/01 9:00:00", "2022/09/02 18:00:00", "2022/09/03 12:00:00", NA, NA, "2022/09/15 18:00:00", "2022/09/18 20:00:00", NA, NA, NA), score = c(243, 232, 319, NA, NA, 436, 310, NA, NA, NA), treatment_start = c(NA, NA, NA, "2022/09/02 8:00:00", "2022/09/03 11:00:00", NA, NA, "2022/09/15 8:00:00", "2022/09/16 14:00:00", "2022/09/16 23:00:00" ), treatment_end = c(NA, NA, NA, "2022/09/02 22:00:00", "2022/09/09 12:00:00", NA, NA, "2022/09/16 2:00:00", "2022/09/16 22:00:00", "2022/09/17 0:00:00" )), row.names = c(NA, -10L), spec = structure(list(cols = list( ID = structure(list(), class = c("collector_character", "collector" )), score_time = structure(list(), class = c("collector_character", "collector")), score = structure(list(), class = c("collector_double", "collector")), treatment_start = structure(list(), class = c("collector_character", "collector")), treatment_end = structure(list(), class = c("collector_character", "collector"))), default = structure(list(), class = c("collector_guess", "collector")), delim = ","), class = "col_spec"), problems = <pointer: 0x6000000190b0>, class = c("spec_tbl_df", "tbl_df", "tbl", "data.frame"))
表格预览:
| ID | score_time | score | treatment_start | treatment_end |
|---|---|---|---|---|
| A | 2022/09/01 9:00:00 | 243 | NA | NA |
| A | 2022/09/02 18:00:00 | 232 | NA | NA |
| A | 2022/09/03 12:00:00 | 319 | NA | NA |
| A | NA | NA | 2022/09/02 8:00:00 | 2022/09/02 22:00:00 |
| A | NA | NA | 2022/09/03 11:00:00 | 2022/09/09 12:00:00 |
| B | 2022/09/15 18:00:00 | 436 | NA | NA |
| B | 2022/09/18 20:00:00 | 310 | NA | NA |
| B | NA | NA | 2022/09/15 8:00:00 | 2022/09/16 2:00:00 |
| B | NA | NA | 2022/09/16 14:00:00 | 2022/09/16 22:00:00 |
| B | NA | NA | 2022/09/16 23:00:00 | 2022/09/17 0:00:00 |
目标输出(排除不在治疗区间的评分):
# A tibble: 3 × 2 ID score <chr> <dbl> 1 A 232 2 A 319 3 B 436
此前尝试的宽表转换方法无法正确匹配时间区间,需要更高效的合并与匹配方案。
解决方案
核心思路是拆分评分数据与治疗区间数据,按ID交叉匹配后筛选符合条件的记录,使用tidyverse+lubridate实现:
library(tidyverse) library(lubridate) # 1. 拆分并清洗数据 # 提取有效评分记录,转换时间格式 score_data <- data %>% filter(!is.na(score_time)) %>% mutate(score_time = ymd_hms(score_time)) %>% select(ID, score_time, score) # 提取有效治疗区间记录,转换时间格式并生成区间对象 treatment_data <- data %>% filter(!is.na(treatment_start)) %>% mutate( treatment_start = ymd_hms(treatment_start), treatment_end = ymd_hms(treatment_end), trt_interval = interval(treatment_start, treatment_end) ) %>% select(ID, trt_interval) # 2. 交叉匹配并筛选结果 result <- score_data %>% inner_join(treatment_data, by = "ID") %>% filter(score_time %within% trt_interval) %>% distinct(ID, score) %>% # 去除同一评分匹配多个区间的重复行 arrange(ID) # 输出结果 result
代码解释
数据拆分与清洗
- 从原始数据中分离出无NA的评分记录和治疗区间记录,避免无效数据干扰
- 用
ymd_hms()将字符型时间转换为lubridate可识别的时间格式,为后续区间匹配做准备
交叉匹配与筛选
- 通过
inner_join()按ID将评分数据与治疗区间数据全连接,让每条评分记录对应同一个ID的所有治疗区间 - 使用lubridate的
%within%运算符直接判断评分时间是否落在某个治疗区间内
- 通过
结果整理
- 用
distinct()去除同一评分匹配多个区间产生的重复行 - 按ID排序得到最终的目标结果
- 用
该方案逻辑清晰,避免了宽表转换的复杂操作,在多ID多区间的场景下效率更高。
内容的提问来源于stack exchange,提问作者KintensT
相关产品推荐
相关产品推荐

