如何在R中简洁实现多列ICD-10诊断编码的匹配标记?
问题:简洁筛选多列中的ICD-10编码
我想从数据集的诊断变量里筛选出特定的ICD-10编码,以此标记符合条件的受试者,但找不到简洁的实现方式。
背景
每个受试者ID对应50多个诊断实例,分别存在Disease_code_1、Disease_code_2……这类列中,同时配有对应的诊断日期列。示例数据如下:
df = data.frame(ID = c(1001, 1002, 1003, 1004, 1005), Disease_code_1 = c('I802', 'G200','I802',NA, 'H356'), Disease_code_2 = c('A071',NA,'G20',NA,'I802'), Disease_code_3 = c('H250', NA,NA,NA,NA), Date_of_diagnosis_1 = c('12/06/1997','13/06/1997','14/02/2003',NA,'18/03/2005'), Date_of_diagnosis_2 = c('12/06/1998',NA,'18/09/2001',NA,'12/07/1993'), Date_of_diagnosis_3 = c('17/09/2010',NA,NA,NA,NA)) # 输出结果 ID Disease_code_1 Disease_code_2 Disease_code_3 Date_of_diagnosis_1 Date_of_diagnosis_2 Date_of_diagnosis_3 1 1001 I802 A071 H250 12/06/1997 12/06/1998 17/09/2010 2 1002 G200 <NA> <NA> 13/06/1997 <NA> <NA> 3 1003 I802 G20 <NA> 14/02/2003 18/09/2001 <NA> 4 1004 <NA> <NA> <NA> <NA> <NA> <NA> 5 1005 H356 I802 <NA> 18/03/2005 12/07/1993 <NA>
可以看到,Disease_code_1和Disease_code_2中都有需要纳入分析的I802编码。
尝试过的方法
错误的简洁写法
我尝试用ifelse加字符串拼接的方式筛选,结果得到的符合条件的受试者数量为0:
data$diagnosis<- with(data, ifelse((data$disease_code_1 == "I802||G200||H356"),1,0)) data$diagnosis[is.na(data$diagnosis)] <- 0 sum(data$diagnosis)
可行但冗长的写法
目前唯一能运行的写法非常冗长,而实际场景中有50多个诊断列和12个目标编码,代码会变得异常繁琐甚至无法正常运行(命令行持续出现+符号):
data$diagnosis <- with(data, ifelse(((data$disease_code_1 == "I802")|(data$disease_code_1 == "G200")|(data$disease_code_1 == "H356")|(data$disease_code_2 == "I802")|(data$disease_code_2 == "G200")|(data$disease_code_2 == "H356")|(data$disease_code_3 == "I802")|(data$disease_code_3 == "G200")|(data$disease_code_3 == "H356")), 1, 0)) data$diagnosis[is.na(data$diagnosis)] <- 0 sum(data$diagnosis)
简洁解决方案
方法1:使用tidyverse转为长格式处理
这种方法更直观,适合处理多列重复结构的数据:
library(tidyverse) # 定义目标编码 target_codes <- c("I802", "G200", "H356") # 把宽格式转为长格式,只保留诊断编码列 df_long <- df %>% pivot_longer(cols = starts_with("Disease_code"), names_to = "code_col", values_to = "code") %>% filter(!is.na(code)) # 标记符合条件的ID,再合并回原数据 df <- df %>% left_join(df_long %>% group_by(ID) %>% summarise(diagnosis = any(code %in% target_codes) %>% as.integer()), by = "ID") %>% replace_na(list(diagnosis = 0)) # 查看结果 sum(df$diagnosis)
方法2:Base R 一行式处理
如果不想加载额外包,可以用Base R的方法,直接对诊断列进行批量判断:
# 定义目标编码 target_codes <- c("I802", "G200", "H356") # 筛选所有诊断列 code_cols <- grep("^Disease_code", names(df), value = TRUE) # 逐行判断是否有任意一个编码在目标列表中 df$diagnosis <- as.integer(rowSums(sapply(df[code_cols], function(x) x %in% target_codes), na.rm = TRUE) > 0) # 查看结果 sum(df$diagnosis)
解释
- 两种方法都先定义了目标编码列表
target_codes,方便后续修改维护 - 方法1通过转长格式,把所有诊断编码集中到一列,再按ID判断是否存在目标编码,逻辑清晰
- 方法2用
sapply批量处理所有诊断列,每行计算符合条件的数量,只要大于0就标记为1,高效简洁
内容的提问来源于stack exchange,提问作者Nic
相关产品推荐
相关产品推荐

