如何在R中基于多因子列生成符合特定NA规则的新列
R中基于多列高效生成新列的解决方案(处理含NA的调查数据)
需求说明
需要在tibble中生成新列,规则如下:
- 仅当用于生成新列的所有目标列均为NA时,新列返回NA
- 若目标列中至少有一列值为"yes",新列返回"yes"
- 若目标列中没有"yes"且不全为NA,新列返回"no"
示例数据(Reprex)
library(tidyverse) # 创建示例数据集 df <- tibble( othervar_2007 = c(NA, "yes", "no", "no", "no"), morv1_2007 = c(NA, "yes", "no", "no", NA), morv2_2007 = c(NA, "yes", NA, "no", "no"), morv3_2007 = c(NA, "no", "yes", "no", "no"), morv4_2007 = c(NA, "no", "no", "no", "no"), morv_othervar = c(NA, "yes", "no", "no", "no") ) # 查看数据集 df #> # A tibble: 5 × 6 #> othervar_2007 morv1_2007 morv2_2007 morv3_2007 morv4_2007 morv_othervar #> <chr> <chr> <chr> <chr> <chr> <chr> #> 1 <NA> <NA> <NA> <NA> <NA> <NA> #> 2 yes yes yes no no yes #> 3 no no <NA> yes no no #> 4 no no no no no no #> 5 no <NA> no no no no
现有方案的问题
方案1(case_when逐个列判断):
df <- df %>% mutate(newvar1 = case_when( morv1_2007 == "yes" | morv2_2007 == "yes" | morv3_2007 == "yes" | morv4_2007 == "yes" ~ "Yes", morv1_2007 == "no" | morv2_2007 == "no" | morv3_2007 == "no" | morv4_2007 == "no" ~ "No" ))可行但列数较多时操作繁琐,无法使用
starts_with/ends_with等列选择器批量指定目标列。方案2(rowwise + rowSums):
df <- df %>% rowwise %>% mutate(newvar2 = if_else(rowSums(across(c(morv1_2007, morv2_2007, morv3_2007, morv4_2007), ~ .x == "yes"))>0, "Yes", "No"))只要目标列存在一个NA就返回NA;添加
na.rm=TRUE后,全NA行会错误返回"No",不符合需求。方案3(rowwise + c_across):
df <- df %>% rowwise %>% mutate(newvar3 = if(all(is.na(c_across(matches("^morv.*2007$"))))) { NA_character_ } else if ("yes" %in% c_across(matches("^morv.*2007$"))) { "yes" } else { "no" })符合需求但
rowwise逐行处理效率极低,处理大数据集时速度很慢。
高效解决方案
使用向量化的if_all/if_any函数替代rowwise,无需逐行遍历,大幅提升运行效率,同时支持列选择器批量指定目标列:
df <- df %>% mutate( newvar = case_when( # 所有目标列均为NA时返回NA if_all(matches("^morv.*2007$"), is.na) ~ NA_character_, # 至少有一个目标列是"yes"时返回"yes" if_any(matches("^morv.*2007$"), ~ .x == "yes") ~ "yes", # 其余情况返回"no" TRUE ~ "no" ) ) # 验证结果 df %>% select(starts_with("morv") & ends_with("2007"), newvar) #> # A tibble: 5 × 5 #> morv1_2007 morv2_2007 morv3_2007 morv4_2007 newvar #> <chr> <chr> <chr> <chr> <chr> #> 1 <NA> <NA> <NA> <NA> <NA> #> 2 yes yes no no yes #> 3 no <NA> yes no yes #> 4 no no no no no #> 5 <NA> no no no no
方案优势
- 高效:基于向量化操作,避免
rowwise的逐行开销,处理大数据集时速度提升明显 - 灵活:通过
matches/starts_with/ends_with等列选择器批量指定目标列,无需逐个列名输入 - 精准:完全符合需求中的NA处理规则
内容的提问来源于stack exchange,提问作者larsroarf
相关产品推荐
相关产品推荐

