You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

方案优势

  1. 高效:基于向量化操作,避免rowwise的逐行开销,处理大数据集时速度提升明显
  2. 灵活:通过matches/starts_with/ends_with等列选择器批量指定目标列,无需逐个列名输入
  3. 精准:完全符合需求中的NA处理规则

内容的提问来源于stack exchange,提问作者larsroarf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 17:19:52