如何实现基于数据框逻辑列值生成变量名列的可扩展方案?
动态生成逻辑变量对应的变量名列
问题背景
现有如下数据框:
id <- seq(1:4) var_1 <- c(TRUE, FALSE, FALSE, FALSE) var_2 <- c(FALSE, TRUE, FALSE, FALSE) var_3 <- c(FALSE, TRUE, FALSE, FALSE) var_4 <- c(FALSE, FALSE, TRUE, FALSE) var_5 <- c(FALSE, TRUE, TRUE, FALSE) df <- data.frame(id, var_1, var_2, var_3, var_4, var_5)
输出结果:
id var_1 var_2 var_3 var_4 var_5 1 1 TRUE FALSE FALSE FALSE FALSE 2 2 FALSE TRUE TRUE FALSE TRUE 3 3 FALSE FALSE FALSE TRUE TRUE 4 4 FALSE FALSE FALSE FALSE FALSE
需求是遍历每一行,将值为TRUE的列名拼接成字符串存入新列result;无TRUE值的行,result设为NA,预期结果如下:
id var_1 var_2 var_3 var_4 var_5 result 1 1 TRUE FALSE FALSE FALSE FALSE var_1 2 2 FALSE TRUE TRUE FALSE TRUE var_2, var_3, var_5 3 3 FALSE FALSE FALSE TRUE TRUE var_4, var_5 4 4 FALSE FALSE FALSE FALSE FALSE <NA>
现有代码硬编码了逻辑列的范围(var_1:var_5),无法适配任意数量的逻辑变量:
library(tidyverse) df |> mutate(across(where(is.logical), ~ case_when(.x ~ cur_column()), .names = "{.col}")) |> unite("result", var_1:var_5, sep = ", ", na.rm = TRUE)
可扩展解决方案
方法1:Tidyverse 动态适配版
通过where()函数动态识别逻辑列,无需指定具体列名,同时处理空值为NA:
library(tidyverse) df_processed <- df %>% # 将逻辑列替换为列名(TRUE时)或NA(FALSE时) mutate(across(where(is.logical), ~ if_else(.x, cur_column(), NA_character_))) %>% # 拼接所有字符型的逻辑列转换结果 unite(result, where(is.character), sep = ", ", na.rm = TRUE) %>% # 将空字符串转为NA,符合需求 mutate(result = if_else(result == "", NA_character_, result)) print(df_processed)
方法2:Base R 实现
无需依赖tidyverse,通过动态筛选逻辑列实现:
# 筛选所有逻辑类型的列名 logic_column_names <- names(df)[sapply(df, is.logical)] # 逐行处理,拼接符合条件的列名 df$result <- apply(df[logic_column_names], 1, function(row_values) { # 获取当前行中值为TRUE的列名 matched_cols <- logic_column_names[row_values] # 无匹配则返回NA,否则拼接字符串 if (length(matched_cols) == 0) NA_character_ else paste(matched_cols, collapse = ", ") }) print(df)
两种方法都能自动适配任意数量的逻辑列,无需修改代码中的列名范围。
内容的提问来源于stack exchange,提问作者JontroPothon
相关产品推荐
相关产品推荐

