如何简洁地在R数据集中提取最早诊断记录及对应编码?
问题
我有一个R数据集,需要确定每个ID对应的最早疾病诊断及关联编码。当前数据集的首个疾病编码并不总是对应最早诊断(如ID 1005所示)。数据集示例如下:
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))
我目前通过创建多个子集、行绑定后筛选最早诊断的方式实现需求,代码如下:
Disease_1 <- as.data.frame((cbind(df$ID, df$Disease_code_1, df$Date_of_diagnosis_1))) Disease_2 <- as.data.frame((cbind(df$ID, df$Disease_code_2, df$Date_of_diagnosis_2))) Disease_3 <- as.data.frame((cbind(df$ID, df$Disease_code_3, df$Date_of_diagnosis_3))) Disease_data <- rbind(Disease_1, Disease_2, Disease_3) colnames(Disease_data) = c("id","Disease_code","Date_of_diagnosis") #筛选每个参与者的最早诊断记录 Disease_data <- Disease_data [order(Disease_data [,'id'],Disease_data [,'Date_of_diagnosis']),] Disease_data <- Disease_data [!duplicated(Disease_data $id),]
但实际数据中有25组类似的疾病编码与诊断日期变量对,当前方法代码冗余。我想知道是否可以使用startsWith命令来简化代码,此前尝试未成功。
解决方案
方法一:基础R结合startsWith实现
完全用基础R的startsWith批量识别目标列,避免手动重复创建子集,步骤如下:
- 用
startsWith筛选所有疾病编码和诊断日期列,搭配ID列构建长格式数据 - 清理缺失值并转换日期格式
- 按ID排序后筛选最早诊断记录
代码示例:
# 提取ID列、所有疾病编码列、所有诊断日期列 id_col <- df$ID disease_cols <- df[, startsWith(colnames(df), "Disease_code_")] date_cols <- df[, startsWith(colnames(df), "Date_of_diagnosis_")] # 转换为长格式:每个ID的每组诊断对应一行 long_data <- data.frame( ID = rep(id_col, ncol(disease_cols)), Disease_code = as.vector(as.matrix(disease_cols)), Date_of_diagnosis = as.vector(as.matrix(date_cols)) ) # 清理缺失值,转换日期格式(注意是日/月/年的格式) long_data <- long_data[!is.na(long_data$Disease_code) & !is.na(long_data$Date_of_diagnosis), ] long_data$Date_of_diagnosis <- as.Date(long_data$Date_of_diagnosis, format = "%d/%m/%Y") # 按ID和诊断日期排序,保留每个ID的第一条记录(即最早诊断) long_data <- long_data[order(long_data$ID, long_data$Date_of_diagnosis), ] result <- long_data[!duplicated(long_data$ID), ] print(result)
方法二:tidyverse工具简化(更直观)
如果习惯使用tidyverse生态,pivot_longer可以更高效地完成数据重塑,代码更简洁:
library(tidyverse) result <- df %>% # 将多组疾病编码/日期列转为长格式 pivot_longer( cols = -ID, names_to = c(".value", "group"), names_pattern = "(Disease_code|Date_of_diagnosis)_(\\d+)" ) %>% # 去除含缺失值的记录 drop_na(Disease_code, Date_of_diagnosis) %>% # 转换日期格式 mutate(Date_of_diagnosis = as.Date(Date_of_diagnosis, format = "%d/%m/%Y")) %>% # 按ID和日期排序 arrange(ID, Date_of_diagnosis) %>% # 保留每个ID的第一条记录 distinct(ID, .keep_all = TRUE) print(result)
两种方法都能适配25组变量的场景,无需手动重复编写子集代码。
内容的提问来源于stack exchange,提问作者Nic
相关产品推荐
相关产品推荐

