基于多列值创建新变量:在R数据框中提取含1值的列名
解决R语言DataFrame生成新变量的需求
嘿,我来帮你搞定这个需求!先明确下你的目标:你有一个三列的DataFrame,要新增一个变量,每一行对应的值是该行里等于"1"的单元格所在的列名;如果一行没有"1"就返回NA,要是有多个"1",咱们还能把对应的列名用逗号拼接起来。
第一步:先确认你的原始数据
先把你的数据代码贴出来,方便后续操作:
MO1 <- c("0","1","2","3") MO2 <- c("1","0","3","2") MO3 <- c("3","2","1","0") df <- data.frame(MO1, MO2, MO3)
方法一:用Base R快速实现
这是最直接的方案,用apply()函数逐行处理:
# 新增名为has_one的变量 df$has_one <- apply(df, 1, function(row) { # 筛选出当前行值为"1"的列名 target_cols <- names(df)[row == "1"] # 处理不同情况:有匹配就拼接,没有就返回NA if (length(target_cols) > 0) { paste(target_cols, collapse = ", ") } else { NA_character_ } }) # 查看最终结果 print(df)
运行后你会得到预期结果:
MO1 MO2 MO3 has_one 1 0 1 3 MO2 2 1 0 2 MO1 3 2 3 1 MO3 4 3 2 0 <NA>
方法二:用Tidyverse工具链实现(适合熟悉tidy风格的用户)
如果你平时习惯用dplyr和tidyr,可以用宽转长的思路处理,这种方法更直观,也方便后续扩展:
library(dplyr) library(tidyr) df_new <- df %>% # 给每行加行号,方便后续分组 mutate(row_id = row_number()) %>% # 把宽格式转成长格式 pivot_longer(-row_id, names_to = "col_name", values_to = "value") %>% # 筛选出值为"1"的记录 filter(value == "1") %>% # 按行号分组,拼接同一行的匹配列名 group_by(row_id) %>% summarise(has_one = paste(col_name, collapse = ", ")) %>% # 合并回原始数据,保留所有行(包括无"1"的行) right_join(df %>% mutate(row_id = row_number()), by = "row_id") %>% # 去掉临时行号列 select(-row_id) %>% # 把新变量移到最后一列,方便查看 relocate(has_one, .after = last_col()) # 查看结果 print(df_new)
这个方法得到的结果和Base R方案完全一致,要是你的DataFrame列数多、后续还要做更多处理,这种tidy风格的代码会更易读和维护。
内容的提问来源于stack exchange,提问作者garrettsmith
相关产品推荐
相关产品推荐

