0

I would like to create a single column by conditional logic across multiple columns. This is a minimal reproducible example. As you can see, the double bang seems to cause evaluation of the .x before the anonymous function is defined. Any ideas for a solution on this one that would allow me to map over a list of targets?

library(magrittr)
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
df <- data.frame(
  stringsAsFactors = FALSE,
  Well.Position = c("C23", "C24", "D23", "D24"),
  S = c(28.65475574, 28.06971218, 28.04204381, 29.45081936),
  N = c(29.67113762, 29.65467395, 30.00612006, 29.65156431)
)

targets <- c("S", "N")
# works
df %>% 
  dplyr::mutate(PASS =  !!sym(targets[1]) <= 37)
#>   Well.Position        S        N PASS
#> 1           C23 28.65476 29.67114 TRUE
#> 2           C24 28.06971 29.65467 TRUE
#> 3           D23 28.04204 30.00612 TRUE
#> 4           D24 29.45082 29.65156 TRUE
# does not work
df %>% 
  dplyr::mutate(PASS = all(purrr::map_lgl(targets, ~ (!!sym(.x) <= 37))))                
#> Error in is_symbol(x): object '.x' not found
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213

2 Answers2

0

You can use if_any -

library(dplyr)

df %>% mutate(PASS = if_any(all_of(targets), ~.x <= 37))

#  Well.Position        S        N PASS
#1           C23 28.65476 29.67114 TRUE
#2           C24 28.06971 29.65467 TRUE
#3           D23 40.00000 30.00612 TRUE
#4           D24 29.45082 29.65156 TRUE
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
  • I appreciate the suggestion. I'll play around with this a bit, but what you've proposed doesn't quite work. It's the wrong logic. For instance, if I change one of the values to 38, the output is still true, while it should only be true if both targets <= 37 – user2376418 Aug 17 '21 at 22:29
  • The solution was to swap `if_any()` for `if_all()`. Thank you! – user2376418 Aug 17 '21 at 22:32
0

Two ways:

  1. pmap
df %>% 
  dplyr::mutate(PASS = pmap_lgl(select(., !!targets), ~ all(c(...) < 30)))
  1. rowwise
df %>% 
  rowwise %>% 
  mutate(PASS = all(c_across(!!targets) < 30))