在R中按列值条件合并行:合并间隔不足1小时的用药记录
我来帮你搞定这个合并连续用药记录的需求!你的核心思路是对的,但现有代码里的循环逻辑和dplyr的使用方式有问题,咱们用tidyverse的工具来更优雅地解决这个问题,完全不需要复杂的循环。
解决方案代码
library(tidyverse) library(lubridate) merge_pressor_doses <- function(df) { df %>% # 先按患者ID和起始时间排序,确保记录是按时间顺序排列的 arrange(icustay_id, starttime) %>% group_by(icustay_id) %>% # 计算当前记录的starttime与上一条记录的endtime的时间差(转换为分钟) # 第一条记录没有上一条,所以时间差设为NA mutate(interval = as.duration(starttime - lag(endtime)) / dminutes(1)) %>% # 创建分组标识:当间隔>=60分钟(或第一条记录)时,新建一个组 mutate(group_id = cumsum(is.na(interval) | interval >= 60)) %>% # 按患者ID和分组标识聚合,应用合并规则 group_by(icustay_id, group_id) %>% summarise( starttime = min(starttime), endtime = max(endtime), vaso_rate = mean(vaso_rate), vaso_amount = sum(vaso_amount), .groups = "drop" # 取消分组,返回普通数据框 ) %>% # 移除临时的group_id列,保持输出整洁 select(-group_id) } # 测试函数 merged_df <- merge_pressor_doses(df) print(merged_df)
代码逻辑拆解
咱们一步步捋清楚这个实现:
- 排序:先用
arrange确保每个患者的记录按时间先后排列,这是后续计算间隔的基础,否则间隔判断会出错。 - 计算时间间隔:用
lag(endtime)获取当前记录的上一条记录的结束时间,再计算两条记录的时间差并转换为分钟数。第一条记录没有上一条,所以lag(endtime)返回NA,对应的interval也是NA。 - 生成分组标识:用
cumsum来创建分组ID——每当遇到间隔≥60分钟的情况(或者是第一条记录),就累加1,这样连续的、间隔不足1小时的记录会被分到同一个组里。 - 聚合计算:按患者ID和分组ID分组后,严格按照你的需求聚合:取最早的
starttime、最晚的endtime,vaso_rate取平均值,vaso_amount求和。 - 清理输出:最后移除临时的
group_id列,让输出格式和你期望的一致。
测试结果
运行代码后,你会得到符合预期的输出:
icustay_id starttime endtime vaso_rate vaso_amount <dbl> <dttm> <dttm> <dbl> <dbl> 1 1 2019-09-10 13:20:00 2019-09-12 01:20:00 6 896. 2 1 2019-09-14 16:40:00 2019-09-15 16:40:00 4 209. 3 2 2019-09-10 12:40:00 2019-09-13 13:20:00 2 864. 4 3 2019-09-10 01:20:00 2019-09-11 13:20:00 9 405.
(注:icustay_id=1的前两条记录合并后,vaso_rate是(3+9)/2=6,vaso_amount是293+603≈896,这是符合合并规则的正确结果)
原有代码的问题说明
简单说几个关键问题:
- 执行
df %>% arrange(...)后没有把结果赋值回df,导致排序操作根本没生效 - 循环里的
which(df$icustay_id==i) && j < max(...)逻辑错误,不能将索引向量和布尔值直接混合使用 - 使用
mutate时没有保存结果,且df$starttime[j+1]这种写法不符合dplyr的向量式操作逻辑 - 最后
return(df)返回的是原数据框,不是聚合后的结果
用tidyverse的窗口函数(比如lag、cumsum)处理这种连续分组的问题,比循环高效得多,也更易读和维护。
内容的提问来源于stack exchange,提问作者Eric Yamga
相关产品推荐
相关产品推荐

