Home > Software design >  How to pass tidyselect::starts_with(...) etc. to dplyr function(s)?
How to pass tidyselect::starts_with(...) etc. to dplyr function(s)?

Time:06-30

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))

CodePudding user response:

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

CodePudding user response:

Does this work?

test %>%
  rowwise() %>%
  mutate(new_col=sum(across(starts_with('var')), na.rm = T)) %>%
  ungroup()
var1  var2  var3 do_not_touch new_col
  <dbl> <dbl> <dbl>        <int>   <dbl>
1    NA    NA    NA            1       0
2     1    NA     0            2       1
3     2     3     0            3       5

Now if you want to replace the 0 with NA you can put an ifelse there

test %>%
  rowwise() %>%
  mutate(new_col=sum(across(starts_with('var')), na.rm = T)) %>%
  ungroup() %>%
  mutate(new_col=ifelse(new_col==0, NA, new_col))
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
  • Related