R中无需循环为数据框添加同一患者30天内Inpatient事件求和列
当然有啦!在R里处理这种「同一患者过去30天内事件统计」的需求,完全不用写繁琐的for循环,用矢量化的工具包就能高效搞定。下面给你两种常用的实现方式,适配不同的使用习惯:
方法一:用dplyr + slider(适合tidyverse用户)
这个组合语法直观,容易理解,尤其适合已经熟悉tidyverse工作流的同学。核心是用slider包的滑动窗口函数,基于日期索引精准计算过去30天的总和。
首先确保你的数据按「患者ID」和「事件日期」排序,然后分组计算:
library(dplyr) library(slider) # 假设你的数据框结构如下(可替换成你的真实数据) df <- tibble( patient_id = c(1, 1, 1, 2, 2), event_date = as.Date(c("2023-01-01", "2023-01-15", "2023-02-05", "2023-03-01", "2023-03-25")), # 先把Inpatient事件转成0/1数值(如果原数据是字符型的话) is_inpatient = ifelse(event_type == "Inpatient", 1, 0) ) # 核心处理步骤 df_processed <- df %>% arrange(patient_id, event_date) %>% # 按患者+日期排序,确保窗口顺序正确 group_by(patient_id) %>% # 按患者分组 mutate( past_30d_inpatient_sum = slide_index_sum( .x = is_inpatient, # 要求和的变量 .i = event_date, # 作为索引的日期列 .before = days(30), # 窗口范围:当前日期往前30天 .complete = FALSE # 即使窗口不满30天也计算(如需满30天则设为TRUE) ) ) %>% ungroup()
关键说明:
slide_index_sum会自动针对每个患者,以event_date为基准,只统计过去30天内的事件,完全不用手动循环;- 如果你的「Inpatient」事件是分类变量(比如"住院"/"非住院"),记得先转成0/1的数值型,这样才能求和。
方法二:用data.table(适合大数据场景)
如果你的数据量很大(比如几十万甚至上百万行),data.table的速度优势会非常明显。这里推荐用非等自连接的方式,精准匹配每个行对应的30天窗口:
library(data.table) # 转换为data.table格式 setDT(df) # 先按患者ID和日期排序 setorder(df, patient_id, event_date) # 非等连接计算过去30天内的住院事件总和 df[, past_30d_inpatient_sum := df[df, sum(is_inpatient), on = .( patient_id, event_date >= event_date - days(30), # 窗口起始:当前日期-30天 event_date <= event_date # 窗口结束:当前日期 ), by = .EACHI]$V1]
关键说明:
- 非等连接的方式逻辑非常直接:对每一行,找到同一个患者、且事件日期在「当前日期-30天」到「当前日期」之间的所有行,然后求和
is_inpatient; - 这种方法的计算效率极高,处理大数据时比dplyr组合快很多。
重要注意事项
- 确保
event_date是Date类型:如果原数据是字符型,记得用as.Date(event_date)转换; - 必须先排序:不管用哪种方法,都要先按患者ID和事件日期排序,否则窗口计算会出错;
- 窗口范围的调整:如果不想包含当前日期的事件,可以把
event_date <= event_date改成event_date < event_date。
内容的提问来源于stack exchange,提问作者Philipp L
相关产品推荐
相关产品推荐

