Search code examples
rif-statementdplyrtidyselect

How to pass tidyselect::starts_with(...) etc. to dplyr function(s)?


I would like to pass a column selection to a dplyr function (across) inside an ifelse statement.

This is my data:

tibble(var1 = c(NA,1,2),
       var2 = c(NA,NA,3),
       var3 = c(NA,0,0),
       do_not_touch = c(1:3)
       ) -> test

This is what I was trying:

test %>% 
  mutate( new_col = test %>% 
            select(starts_with("var")) %>% 
            ifelse(if_all(., is.na), NA, rowSums(across(.), na.rm=T)) )

This is what I was expecting:

# A tibble: 3 x 5
   var1  var2  var3 do_not_touch new_col
  <dbl> <dbl> <dbl>        <int>   <dbl>
1    NA    NA    NA            1      NA
2     1    NA     0            2       1
3     2     3     0            3       5

This is what I got:

Error in `mutate_cols()`:
! Problem with `mutate()` column `new_col`.
i `new_col = test %>% select(starts_with("var")) %>% ...`.
x unused argument (rowSums(across(.), na.rm = T))
Caused by error in `ifelse()`:
! unused argument (rowSums(across(.), na.rm = T))

Solution

  • One option would be:

    library(dplyr)
    
    test %>%
      mutate(new_col = ifelse(
        if_all(starts_with("var"), is.na), 
        NA, 
        rowSums(across(starts_with("var")), na.rm = TRUE)))
    #> # A tibble: 3 × 5
    #>    var1  var2  var3 do_not_touch new_col
    #>   <dbl> <dbl> <dbl>        <int>   <dbl>
    #> 1    NA    NA    NA            1      NA
    #> 2     1    NA     0            2       1
    #> 3     2     3     0            3       5
    

    Or more in spirit of your try:

    test %>%
      mutate(select(., starts_with("var")) %>% 
               transmute(new_col = ifelse(
                 if_all(.fns = is.na), 
                 NA, 
                 rowSums(across(), na.rm = TRUE))))
    #> # A tibble: 3 × 5
    #>    var1  var2  var3 do_not_touch new_col
    #>   <dbl> <dbl> <dbl>        <int>   <dbl>
    #> 1    NA    NA    NA            1      NA
    #> 2     1    NA     0            2       1
    #> 3     2     3     0            3       5