如何用dplyr批量提取多列首字符并合并为新列?
问题:批量提取诊断码首字符并拼接成新列
我有一个数据集,包含100个字符型诊断字段,命名为DiagnosisCode1至DiagnosisCode100。多数情况下第一个诊断字段完整,但并非总是如此,序号较高的字段几乎全为NA。我需要提取这些字段的首字符并合并为一个名为OnsetFlags的新列。由于字段数量多,我不想显式引用所有100个字段,希望使用dplyr的starts_with()等辅助函数或DiagnosisCode1:DiagnosisCode100这样的范围来指代。
示例数据
example = structure(list(id = c("1", "2", "3", "4", "5", "6", "7"), DiagnosisCode1 = c("2G56.2", "2M48.06", "2G56.2", "2G56.0", "2S83.53", "2M23.20", "2S83.53" ), DiagnosisCode2 = c("2G56.0", "2G55.3", "2G56.0", "2G56.2", "2Y92.82", "2Z86.43", "2S83.2"), DiagnosisCode3 = c("2Z86.43", "2Z86.43", "2Z86.43", "1J98.1", "2V93.8", NA, "2W19"), DiagnosisCode4 = c(NA, "2U82.3", NA, "2U80.2", "2U73.8", NA, "2Y92.39"), DiagnosisCode5 = c(NA, "2U83.3", NA, NA, NA, NA, "2U56.39")), row.names = c(NA, -7L), class = "data.frame")
期望结果
新增OnsetFlags列,将各诊断列首字符拼接(自动忽略NA值),示例结果如下:
id DiagnosisCode1 DiagnosisCode2 DiagnosisCode3 DiagnosisCode4 DiagnosisCode5 OnsetFlags 1 1 2G56.2 2G56.0 2Z86.43 <NA> <NA> 222 2 2 2M48.06 2G55.3 2Z86.43 2U82.3 2U83.3 22222 3 3 2G56.2 2G56.0 2Z86.43 <NA> <NA> 222 4 4 2G56.0 2G56.2 1J98.1 2U80.2 <NA> 2212 5 5 2S83.53 2Y92.82 2V93.8 2U73.8 <NA> 222 6 6 2M23.20 2Z86.43 <NA> <NA> <NA> 22 7 7 2S83.53 2S83.2 2W19 2Y92.39 2U56.39 22222
我的尝试
我尝试使用dplyr的across()函数:
# create onset flag array example = example %>% mutate(OnsetFlags = across(starts_with("DiagnosisCode"), ~ as.character(substr(., 1, 1)) ))
但这生成了一个包含多个子列的tibble列,我难以将其提取并合并为数据框的一列,感觉这个方法过于复杂,想知道是否有更简便的解决方法。
解决方案
方法1:dplyr原生方案(rowwise() + c_across())
这是dplyr推荐的行级处理方式,c_across()能在rowwise()环境中获取每行指定列的向量,结合substr()提取首字符后,用paste()自动忽略NA并拼接:
library(dplyr) example <- example %>% rowwise() %>% mutate(OnsetFlags = paste(substr(c_across(starts_with("DiagnosisCode")), 1, 1), collapse = "", na.rm = TRUE)) %>% ungroup()
方法2:基础R结合dplyr(apply()按行处理)
如果不想用rowwise(),可以用apply()直接对诊断列按行操作:
library(dplyr) example <- example %>% mutate(OnsetFlags = apply(select(., starts_with("DiagnosisCode")), 1, function(x) { paste(substr(x, 1, 1), collapse = "", na.rm = TRUE) }))
方法3:临时列中转(tidyr::unite())
先提取所有诊断列的首字符生成临时列,再合并为目标列后删除临时列:
library(dplyr) library(tidyr) example <- example %>% mutate(across(starts_with("DiagnosisCode"), ~ substr(., 1, 1), .names = "temp_{.col}")) %>% unite(OnsetFlags, starts_with("temp"), sep = "", na.rm = TRUE) %>% select(-starts_with("temp"))
内容的提问来源于stack exchange,提问作者Warren Holroyd
相关产品推荐
相关产品推荐

