如何简化基于ICD9编码筛选疾病的R语言grep实现逻辑?
问题描述
我的数据集结构如下:
id ACODE_ICD9_1 ACODE_ICD9_2 ACODE_ICD9_3 <int> <char> <char> <char> 1: 20 463 4660 4720 2: 27 42731 43490 73300 3: 48 40210 2722 43410 4: 52 40210 43410 4139 5: 57 40210 43410 4139 6: 58 40210 43410 4139 7: 59 4660 7242 7245 8: 77 40210 7804 7840 9: 98 42731 7804 78650 10: 101 463 4269 78052 ....
我需要基于ICD9编码筛选对应疾病,当前采用如下代码实现:
disease <- data %>% mutate(AF = ifelse(grepl("^42731", ACODE_ICD9_1) | grepl("^42731", ACODE_ICD9_2) | grepl("^42731", ACODE_ICD9_3), 1, 0), HTN = ifelse(grepl("^401|^402|^403|^404|^405", ACODE_ICD9_1) | grepl("^401|^402|^403|^404|^405", ACODE_ICD9_2) | grepl("^401|^402|^403|^404|^405", ACODE_ICD9_3), 1, 0), DM = ifelse(grepl("^250", ACODE_ICD9_1) | grepl("^250", ACODE_ICD9_2) | grepl("^250", ACODE_ICD9_3), 1, 0)...
由于需要处理的疾病数量较多,当前代码复杂且可读性差,请问是否有更简洁的实现方式?
优化方案
可以通过定义疾病编码映射表+向量化操作来简化代码,大幅提升可读性和可维护性,具体分两步:
1. 定义疾病-ICD9编码规则映射
先把所有疾病对应的ICD9匹配规则整理成一个列表,后续新增/修改疾病只需要调整这个列表即可:
disease_rules <- list( AF = "^42731", HTN = "^401|^402|^403|^404|^405", DM = "^250" # 新增疾病直接在这里添加,比如 Stroke = "^434" )
2. 批量生成疾病标记列
方法一:使用dplyr的if_any(推荐,代码最简洁)
适用于dplyr 1.0.0及以上版本,利用if_any检查每行任意ICD9列是否匹配规则:
library(dplyr) disease <- data %>% mutate( across( .cols = all_of(names(disease_rules)), .fns = ~ if_any(starts_with("ACODE_ICD9"), ~ grepl(disease_rules[[.y]], .x)), .names = "{.col}" ) %>% mutate(across(everything(), as.integer)) # 将布尔值转换为1/0格式 )
方法二:使用purrr批量处理(兼容低版本dplyr)
如果你的dplyr版本较低,用purrr::map_dfc批量生成所有疾病标记列,再与原数据合并:
library(dplyr) library(purrr) disease_flags <- map_dfc(disease_rules, function(pattern) { data %>% rowwise() %>% mutate(flag = any(grepl(pattern, c(ACODE_ICD9_1, ACODE_ICD9_2, ACODE_ICD9_3)))) %>% pull(flag) %>% as.integer() }) disease <- bind_cols(data, disease_flags)
额外优化:处理编码缺失问题
如果数据中存在NA值,可在grepl中添加na.rm = TRUE避免返回NA结果:
# 以if_any方法为例修改 grepl(disease_rules[[.y]], .x, na.rm = TRUE)
内容的提问来源于stack exchange,提问作者Bruce
相关产品推荐
相关产品推荐

