使用case_when处理多个向量

5

我想使用 case_when 根据两个不同的输入来修改/变异一列数据。其中一个用于创建LHS逻辑,另一个在RHS上对应输入值。下面提供了一个示例。

library(dplyr)
library(purrr)
library(tibble)

df <- tibble(var = paste0(rep("var", 10), 1:10),
                 label = c("label1", "label2", rep(NA, 7), "label10"))

match_var <- paste0(rep("var", 7), 3:9)
new_labels <- paste0(rep("add_this_label", 7), 3:9)

df %>% 
  mutate(test = map2(match_var , new_labels,
                     ~case_when(
                       var == .x ~ .y,
                       TRUE ~ label
                     )
  ))

我认为问题在于,case_when 内的所有内容都被视为表达式,但我并不完全确定。可以手动输入 case_when 中的所有七行,但我的应用程序要求在向量 match_varsnew_labels 很长时完成此操作,这使得手动输入 case_when 不可行。

df %>% 
  mutate(label = case_when(
    var == match_var[1] ~ new_labels[1],
    var == match_var[2] ~ new_labels[2],
    var == match_var[3] ~ new_labels[3],
    var == match_var[4] ~ new_labels[4],
    var == match_var[5] ~ new_labels[5],
    var == match_var[6] ~ new_labels[6],
    var == match_var[7] ~ new_labels[7],
    TRUE ~ label
  ))

编辑:可以使用for循环实现所需的结果,但现在我想知道是否可以使用case_whenmap2_*函数来实现?

for (i in seq_along(match_var)) {
  df$label <- ifelse(df$var == match_var[i], new_labels[i], df$label)
}
3个回答

2
我们创建一个命名向量并使用它来匹配“var”中的值,以便将NA元素更改为“new_labels”。最初的回答中已经有这部分内容。
library(tibble)
library(dplyr)
df %>%
    mutate(label = case_when(is.na(label) ~ 
                       deframe(tibble(match_var, new_labels))[var], 
         TRUE ~ label))
# A tibble: 10 x 2
#   var   label          
#   <chr> <chr>          
# 1 var1  label1         
# 2 var2  label2         
# 3 var3  add_this_label3
# 4 var4  add_this_label4
# 5 var5  add_this_label5
# 6 var6  add_this_label6
# 7 var7  add_this_label7
# 8 var8  add_this_label8
# 9 var9  add_this_label9
#10 var10 label10        

注意:可以使用setNames代替deframe创建命名向量。

最初的回答:


这太棒了!如果您不介意,能否解释一下在“case_when”中如何使用命名向量?这与NSE有关吗? - EJJ

1
你可以将新标签加入数据框,并根据需要使用旧标签进行填充。
library("tidyverse")

df <- tibble(var = paste0(rep("var", 10), 1:10),
             label = c("label1", "label2", rep(NA, 7), "label10"))

match_var <- paste0(rep("var", 7), 3:9)
new_label <- paste0(rep("add_this_label", 7), 3:9)

new_labels <-  tibble(match_var, new_label)

df %>%
  left_join(new_labels, by = c("var" = "match_var")) %>%
  mutate(new_label = if_else(is.na(new_label), label, new_label))
#> # A tibble: 10 x 3
#>    var   label   new_label      
#>    <chr> <chr>   <chr>          
#>  1 var1  label1  label1         
#>  2 var2  label2  label2         
#>  3 var3  <NA>    add_this_label3
#>  4 var4  <NA>    add_this_label4
#>  5 var5  <NA>    add_this_label5
#>  6 var6  <NA>    add_this_label6
#>  7 var7  <NA>    add_this_label7
#>  8 var8  <NA>    add_this_label8
#>  9 var9  <NA>    add_this_label9
#> 10 var10 label10 label10

该内容由reprex package(v0.2.1)于2019年3月28日创建


这是一种创新的方法,使用了连接(join)操作,我之前没有考虑过。也许我会选择@akrun的解决方案,因为我想避免使用连接操作以提高性能,但我明天会进行测试。 - EJJ

1

由于您正在比较 == 条件,因此也可以使用具有命名向量的 dplyr::recode 进行操作(请注意需要取消引用拼接 !!!):

df %>%
    mutate(
        label = recode(
            var,
            !!!setNames(new_labels, match_var),
            .default = label
        )
    )

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接