如何在R数据框中按规则对治疗疗程进行连续计数?
按规则为患者标记治疗疗程(Tx Episode)
需求概述
需要基于患者的就诊记录,按照以下规则标记治疗疗程:
- 疗程起始:当月有效就诊(出勤为
Yes)≥4次 - 疗程延续:起始月之后的每个月,有效就诊≥1次
- 疗程终止:起始后任意一月有效就诊<1次,该疗程结束
- 新疗程触发:再次出现月有效就诊≥4次时,开启新疗程(计数递增)
- 不符合上述模式的记录标记为
0
示例输入数据
| Patient ID | 就诊日期 | 出勤情况 |
|---|---|---|
| 1 | 01/01/2023 | Yes |
| 1 | 01/02/2023 | Yes |
| 1 | 01/03/2023 | Yes |
| 1 | 01/04/2023 | Yes |
| 1 | 02/01/2023 | Yes |
| 1 | 03/01/2023 | Yes |
| 1 | 04/01/2023 | No |
| 1 | 05/01/2023 | Yes |
| 1 | 06/01/2023 | No |
| 1 | 07/01/2023 | Yes |
| 1 | 07/02/2023 | Yes |
| 1 | 07/03/2023 | Yes |
| 1 | 07/04/2023 | Yes |
| 1 | 08/01/2023 | Yes |
| ------------ | ------------ | ---------- |
| 2 | 01/01/2023 | Yes |
| 2 | 02/01/2023 | Yes |
| 2 | 03/01/2023 | Yes |
| 2 | 03/02/2023 | Yes |
| 2 | 03/03/2023 | Yes |
| 2 | 03/04/2023 | Yes |
| 2 | 04/01/2023 | Yes |
| 2 | 05/01/2023 | Yes |
| 2 | 07/01/2023 | Yes |
期望输出数据
| Patient ID | 就诊日期 | 出勤情况 | Tx Episode |
|---|---|---|---|
| 1 | 01/01/2023 | Yes | 1 |
| 1 | 01/02/2023 | Yes | 1 |
| 1 | 01/03/2023 | Yes | 1 |
| 1 | 01/04/2023 | Yes | 1 |
| 1 | 02/01/2023 | Yes | 1 |
| 1 | 03/01/2023 | Yes | 1 |
| 1 | 04/01/2023 | No | 0 |
| 1 | 05/01/2023 | Yes | 0 |
| 1 | 06/01/2023 | No | 0 |
| 1 | 07/01/2023 | Yes | 2 |
| 1 | 07/02/2023 | Yes | 2 |
| 1 | 07/03/2023 | Yes | 2 |
| 1 | 07/04/2023 | Yes | 2 |
| 1 | 08/01/2023 | Yes | 2 |
| ------------ | ------------ | ---------- | ------------ |
| 2 | 01/01/2023 | Yes | 0 |
| 2 | 02/01/2023 | Yes | 0 |
| 2 | 03/01/2023 | Yes | 1 |
| 2 | 03/02/2023 | Yes | 1 |
| 2 | 03/03/2023 | Yes | 1 |
| 2 | 03/04/2023 | Yes | 1 |
| 2 | 04/01/2023 | Yes | 1 |
| 2 | 05/01/2023 | Yes | 1 |
| 2 | 07/01/2023 | Yes | 0 |
R解决方案(面向新手)
我们使用tidyverse工具集(包含dplyr用于数据操作,lubridate用于日期处理)来实现需求,步骤清晰易懂:
1. 准备工作:加载包与导入数据
首先安装并加载必要的包,然后导入你的数据集:
# 安装包(首次运行时执行) install.packages(c("tidyverse", "lubridate")) # 加载包 library(tidyverse) library(lubridate) # 导入示例数据(替换为你的实际数据路径) df <- tibble( `Patient ID` = c(1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2), `就诊日期` = c("01/01/2023","01/02/2023","01/03/2023","01/04/2023", "02/01/2023","03/01/2023","04/01/2023","05/01/2023", "06/01/2023","07/01/2023","07/02/2023","07/03/2023", "07/04/2023","08/01/2023","01/01/2023","02/01/2023", "03/01/2023","03/02/2023","03/03/2023","03/04/2023", "04/01/2023","05/01/2023","07/01/2023"), `出勤情况` = c("Yes","Yes","Yes","Yes","Yes","Yes","No","Yes","No", "Yes","Yes","Yes","Yes","Yes","Yes","Yes","Yes","Yes", "Yes","Yes","Yes","Yes","Yes") )
2. 数据预处理:日期转换与月度就诊统计
将字符串格式的就诊日期转换为日期类型,提取年份和月份,并计算每个患者每月的有效就诊次数:
df_processed <- df %>% # 转换日期格式(日/月/年格式用dmy函数) mutate(就诊日期 = dmy(就诊日期), # 提取年月(用于按月份分组统计) year_month = floor_date(就诊日期, "month")) %>% # 按患者和年月分组,统计当月有效就诊次数 group_by(`Patient ID`, year_month) %>% mutate(monthly_yes = sum(`出勤情况` == "Yes")) %>% ungroup()
3. 标记疗程状态与生成Tx Episode
按患者分组,识别疗程的起始、延续和终止状态,最终生成Tx Episode列:
final_df <- df_processed %>% group_by(`Patient ID`) %>% # 按年月排序,确保时间顺序正确 arrange(year_month, .by_group = TRUE) %>% mutate( # 标记是否为疗程起始月(有效就诊≥4) is_start = monthly_yes >= 4, # 标记是否为疗程延续月(前一个月在疗程中,且当月有效就诊≥1) is_continue = lag(in_episode, default = FALSE) & monthly_yes >= 1, # 标记当前是否处于疗程中 in_episode = is_start | is_continue, # 若前一个月在疗程但当月有效就诊<1,终止疗程 in_episode = ifelse(lag(in_episode, default = FALSE) & monthly_yes < 1, FALSE, in_episode), # 累计疗程起始次数,生成唯一疗程编号 episode_num = cumsum(is_start & !lag(in_episode, default = FALSE)) ) %>% # 生成最终Tx Episode列:疗程中用编号,否则为0 mutate(`Tx Episode` = ifelse(in_episode, episode_num, 0)) %>% # 移除中间辅助列,保留原字段和结果列 select(`Patient ID`, `就诊日期`, `出勤情况`, `Tx Episode`) %>% ungroup()
4. 查看与导出结果
运行上述代码后,final_df就是符合要求的数据集,可以查看或导出:
# 查看结果 print(final_df) # 导出为CSV文件 write_csv(final_df, "疗程标记结果.csv")
代码关键说明
floor_date(就诊日期, "month"):将日期统一转换为当月第一天,方便按自然月分组统计monthly_yes:统计每个患者每月的有效就诊次数,是判断疗程的核心依据is_start/is_continue:分别标记疗程的起始和延续条件,明确疗程的边界episode_num:通过累计新疗程的起始次数,自动生成递增的疗程编号
内容的提问来源于stack exchange,提问作者Noah Wolkowicz
相关产品推荐
相关产品推荐

