`if_else` 多个(动态指定的)列的条件

`if_else` condition on multiple (dynamically specified) columns

我正在尝试 mutate 基于多个现有列的值的新列,这样如果任何列等于指定值,if_else 的计算结果为 TRUE。我可以使用 if_else 中的多个比较表达式来执行此操作,但这不起作用,因为我需要使用准引用动态指定列。 Reprex 下面有解释性注释。

如有任何关于如何评估多个动态指定列的比较的建议,我将不胜感激

提前感谢您的帮助!

library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union

mtcars <- head(mtcars, 8)

# Desired output, using individual comparisons for each column
mtcars %>% 
  mutate(color = if_else(
    (gear == 4 | carb == 4), 
    "purple", 
    "green")
  )
#>    mpg cyl  disp  hp drat    wt  qsec vs am gear carb  color
#> 1 21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4 purple
#> 2 21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4 purple
#> 3 22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1 purple
#> 4 21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1  green
#> 5 18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2  green
#> 6 18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1  green
#> 7 14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4 purple
#> 8 24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2 purple

# Failed attempts to do comparisons on multiple columns
mtcars %>% 
  mutate(color = if_else(
    (gear|carb == 4), 
    "purple", 
    "green")
  )
#>    mpg cyl  disp  hp drat    wt  qsec vs am gear carb  color
#> 1 21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4 purple
#> 2 21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4 purple
#> 3 22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1 purple
#> 4 21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1 purple
#> 5 18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2 purple
#> 6 18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1 purple
#> 7 14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4 purple
#> 8 24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2 purple

mtcars %>% 
  mutate(color = if_else(
    (c(gear, carb) == 4), 
    "purple", 
    "green")
  )
#> Error: Problem with `mutate()` input `color`.
#> x Input `color` can't be recycled to size 8.
#> ℹ Input `color` is `if_else((c(gear, carb) == 4), "purple", "green")`.
#> ℹ Input `color` must be size 8 or 1, not 16.

# Using dynamically specified columns and quasiquotation
my_vars <- c("gear", "carb")

# Quasiquotation works with `select`, and `coalesce`
mtcars %>% select(!!!syms(my_vars))
#>                   gear carb
#> Mazda RX4            4    4
#> Mazda RX4 Wag        4    4
#> Datsun 710           4    1
#> Hornet 4 Drive       3    1
#> Hornet Sportabout    3    2
#> Valiant              3    1
#> Duster 360           3    4
#> Merc 240D            4    2
mtcars %>% mutate(any_value = coalesce(!!!syms(my_vars)))
#>    mpg cyl  disp  hp drat    wt  qsec vs am gear carb any_value
#> 1 21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4         4
#> 2 21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4         4
#> 3 22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1         4
#> 4 21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1         3
#> 5 18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2         3
#> 6 18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1         3
#> 7 14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4         3
#> 8 24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2         4

# Desired `mutate`: if any columns (via quasiquotation) == 4, then TRUE
mtcars %>% 
  mutate(color = if_else(
    any(!!!syms(my_vars) == 4), 
    "purple", 
    "green")
  )
#> Error in splice(dot_call(capture_dots, frame_env = frame_env, named = named, : 'list' object cannot be coerced to type 'double'

reprex package (v0.3.0)

于 2020-08-17 创建
mtcars %>%
  mutate(
    flag = eval(parse(text = str_c(my_vars, " == 4", collapse = "|"))),
    color = if_else(flag, "purple", "green")
  ) %>%
  select(-flag)

您可以对要检查的列进行子集化,将它们与值进行比较,然后rowSums计算它们的出现次数并据此分配值。

mtcars$any_value <- ifelse(rowSums(mtcars[my_vars] == 4) > 0, 'purple', 'green')

#Without ifelse
mtcars$any_value <- c('green', 'purple')[(rowSums(mtcars[my_vars] == 4) > 0) + 1]

mtcars
#                   mpg cyl  disp  hp drat    wt  qsec vs am gear carb any_value
#Mazda RX4         21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4    purple
#Mazda RX4 Wag     21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4    purple
#Datsun 710        22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1    purple
#Hornet 4 Drive    21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1     green
#Hornet Sportabout 18.7   8 360.0 175 3.15 3.440 17.02  0  0    3    2     green
#Valiant           18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1     green
#Duster 360        14.3   8 360.0 245 3.21 3.570 15.84  0  0    3    4    purple
#Merc 240D         24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2    purple

tidyverse 方法可以使用 rowwisec_across

library(dplyr)

mtcars %>%
  rowwise() %>%
  mutate(any_value= if(any(c_across(all_of(my_vars)) == 4)) 'purple' else 'green')