R语言:在含指定特征列名的多列中匹配多组字符串并生成标记列
R语言:在含指定特征列名的多列中匹配多组字符串并生成标记列
嗨,我来帮你搞定这个需求!你想要在所有列名包含ttt的列里,批量匹配多组目标字符串,自动生成对应的1/0标记列对吧?之前的写法只能手动指定列名,不够灵活,下面我给你两种通用方案,base R和dplyr的都有,不管列名是ttt1、m0_ttt还是ttt_m0,不管你有多少组匹配规则,都能轻松处理~
先拿你的示例数据(我额外加了一个列名中间含ttt的列,用来验证筛选逻辑):
df <- data.frame( ttt1 = c("METO","LETO","META","LETA","METO"), ttt2 = c("LETO","","METO","","LETA"), m0_ttt = c("META", "", "LETO", "METO", ""), # 列名含ttt的其他形式 other_col = c(1,2,3,4,5) # 无关列,测试不会被选中 )
方案一:dplyr/tidyverse 方案(灵活易扩展)
首先定义你的匹配规则,用列表存起来,以后要加新组直接加一行就行:
match_rules <- list( cl_m = c("METO", "META"), # 匹配这组的标记列叫cl_m cl_l = c("LETO", "LETA") # 匹配这组的标记列叫cl_l )
然后用dplyr的函数批量处理:
library(dplyr) library(purrr) # 用到map_dfc函数 df2 <- df %>% # 遍历所有含ttt的列,生成标记列: bind_cols( map_dfc(match_rules, ~ { # 对当前规则,检查所有含ttt的列是否有值匹配目标字符串 df %>% select(contains("ttt")) %>% # 筛选所有列名含ttt的列 mutate(across(everything(), ~ .x %in% .y & .x != "")) %>% # 每列标记是否匹配且非空 rowSums() %>% # 每行求和,>0表示至少有一列匹配 ifelse(. > 0, 1, 0) # 转成1/0标记 }) )
运行后df2就会自动加上cl_m和cl_l列,而且不管你有多少个含ttt的列,都会被纳入检查~
方案二:base R 方案(无需额外包)
如果你不想加载tidyverse包,用base R也能实现:
同样先定义匹配规则:
match_rules <- list( cl_m = c("METO", "META"), cl_l = c("LETO", "LETA") )
然后筛选出所有列名含ttt的列,再批量生成标记列:
# 找到所有列名包含ttt的列索引 ttt_cols <- grep("ttt", names(df)) # 遍历每个匹配规则,生成对应的标记列 for (rule_name in names(match_rules)) { target_strings <- match_rules[[rule_name]] # 按行检查:该行的含ttt列中是否有值匹配目标字符串且非空 df[[rule_name]] <- apply(df[, ttt_cols], 1, function(row) { as.integer(any(row %in% target_strings & row != "")) }) }
运行后原数据框df就会新增cl_m和cl_l列,效果和dplyr方案一样~
一些实用小提示
- 空值处理:代码里加了
& .x != ""的判断,如果你希望空字符串不算匹配就保留;如果空值需要被当作匹配,删掉这个条件就行。 - 大小写不敏感:如果需要忽略列名的大小写(比如匹配
TTT1或TtT_col),base R里把grep改成grep("ttt", names(df), ignore.case = TRUE);dplyr里改成contains("ttt", ignore.case = TRUE)。 - 扩展规则:以后要加新的匹配组,比如
cl_x = c("XXX", "YYY"),只要在match_rules列表里加一行,代码不用做任何其他修改,自动生成新的标记列~
备注:内容来源于stack exchange,提问作者BPeif
相关产品推荐
相关产品推荐

