Create new variables by combining mutate and case_when in R

Viewed 196

I have dataset with app interactions for different users. App interactions are saved as the number of days the feature has been interacted with by a user, for a specific week. Sample table looks like (commented out ID and weeknr for practical purposes):

tibble(
  #id     = (1, 1, 1), 
  #weeknr = (1, 2, 3), 
  var_1  = c(1, 2, 3, 2, 1),
  var_2  = c(0, 0, 1, 4, 0),
  var_3  = c(1, 1, 1, 0, 0)
)

Goal is now to create three new columns, based on var_{1|3}. If count on app interactions is > 1, assign 1 otherwise 0. I tried the following with no success:

tibble(
  var_1 = c(1, 2, 3, 2, 1),
  var_2 = c(0, 0, 1, 4, 0),
  var_3 = c(1, 1, 1, 0, 0)
) %>% 
  mutate_all(
    funs(case_when(
      . > 0 ~ 1, 
      . == 0 ~ 0, 
      TRUE ~ NA
    ))
  )

Any help is much appreciated!

3 Answers

Making use dplyr::across you could do:

library(dplyr)

tibble(
  var_1 = c(1, 2, 3, 2, 1),
  var_2 = c(0, 0, 1, 4, 0),
  var_3 = c(1, 1, 1, 0, 0)
) %>% 
  mutate(across(everything(), ~ case_when(
      .x > 0 ~ 1, 
      .x == 0 ~ 0, 
      TRUE ~ NA_real_
    ),
    .names = "{.col}_new")
  )
#> # A tibble: 5 × 6
#>   var_1 var_2 var_3 var_1_new var_2_new var_3_new
#>   <dbl> <dbl> <dbl>     <dbl>     <dbl>     <dbl>
#> 1     1     0     1         1         0         1
#> 2     2     0     1         1         0         1
#> 3     3     1     1         1         1         1
#> 4     2     4     0         1         1         0
#> 5     1     0     0         1         0         0

As my first choice is already given by stefan, here an alternative way using bind_cols (generally rarley used) and ifelse:

library(dplyr)
df %>% 
  mutate(across(where(is.numeric), ~ ifelse(. > 0, 1,0))) %>% 
  bind_cols(df)

Output:

  var_1...1 var_2...2 var_3...3 var_1...4 var_2...5 var_3...6
      <dbl>     <dbl>     <dbl>     <dbl>     <dbl>     <dbl>
1         1         0         1         1         0         1
2         1         0         1         2         0         1
3         1         1         1         3         1         1
4         1         1         0         2         4         0
5         1         0         0         1         0         0

Using as.integer or +

library(dplyr)
df %>%
    mutate(across(where(is.numeric), ~ +(. > 0), .names = "{.col}_new"))

-ouputt

# A tibble: 5 x 6
  var_1 var_2 var_3 var_1_new var_2_new var_3_new
  <dbl> <dbl> <dbl>     <int>     <int>     <int>
1     1     0     1         1         0         1
2     2     0     1         1         0         1
3     3     1     1         1         1         1
4     2     4     0         1         1         0
5     1     0     0         1         0         0
Related