如何通过单个conditional mutate为多个变量条件赋值?
如何用单次条件赋值给多个变量
当然可以!你遇到的重复写case_when的问题确实挺烦的,而且left_join对非分类条件(比如数值范围判断)确实不太适用。下面给你几个优雅的解决方案,都能在单次mutate调用里搞定多变量的条件赋值:
方法1:case_when + 迷你tibble + unnest_wider
这是最灵活的方案,不管是分类变量匹配还是连续条件判断都能用。核心思路是让case_when的每个分支返回一个包含目标变量的迷你tibble,再用unnest_wider把这个列表列拆成独立的列:
library(tidyverse) df <- tibble(cat = c("a", "b", "a", "a", "c")) df %>% mutate( # 用case_when返回包含多个变量的tibble temp = case_when( cat == "a" ~ tibble(foo = 1, bar = "three"), cat == "b" ~ tibble(foo = 2, bar = "four"), # 其他情况返回带NA的tibble,注意类型要匹配 TRUE ~ tibble(foo = NA_real_, bar = NA_character_) ) ) %>% # 把列表列拆成独立的foo和bar列 unnest_wider(temp)
如果是连续条件(比如x > 2),直接把cat == "a"换成对应的条件就行,比如:
df %>% mutate(x = c(1, 3, 2, 4, 0)) %>% mutate( temp = case_when( x > 2 ~ tibble(foo = 10, bar = "high"), x <= 2 ~ tibble(foo = 5, bar = "low"), TRUE ~ tibble(foo = NA_real_, bar = NA_character_) ) ) %>% unnest_wider(temp)
方法2:case_match + 列表 + unnest_wider
如果你的条件是精确匹配分类变量,用dplyr::case_match会比case_when语法更简洁:
df %>% mutate( temp = case_match( cat, "a" ~ list(foo = 1, bar = "three"), "b" ~ list(foo = 2, bar = "four"), .default = list(foo = NA_real_, bar = NA_character_) ) ) %>% unnest_wider(temp)
这里用list代替tibble也可以,因为unnest_wider能处理列表类型的列。
方法3:purrr::map + 自定义逻辑
如果你的条件逻辑比较复杂(比如多层嵌套的判断),可以用purrr::map来逐行处理:
df %>% mutate( temp = map(cat, ~{ if (.x == "a") { list(foo = 1, bar = "three") } else if (.x == "b") { list(foo = 2, bar = "four") } else { list(foo = NA_real_, bar = NA_character_) } }) ) %>% unnest_wider(temp)
这种写法自由度很高,适合处理非标准化的条件逻辑。
为什么你之前的尝试没成功?
你之前直接在case_when里返回list("foo" = 1, ...)的思路是对的,但缺少了最后一步展开列表列的操作——case_when会把这个列表当成单个元素的列,必须用unnest_wider把它拆成独立的变量列才行。
内容的提问来源于stack exchange,提问作者pyg
相关产品推荐
相关产品推荐

