How to mutate a column in a dataframe dynamically in R

141 Views Asked by At

I want to mutate the value of a dataframe/tibble column defined as a variable (col_name). I tried with !!col_name without success.

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
col_name <- "b" # the column to select

df <- tibble(a = c(1,2,3), b = c(2,4,6))

df %>%
  mutate(b = if_else((b == 6 & a == 3), 8, b))  # this works 
#> # A tibble: 3 x 2
#>       a     b
#>   <dbl> <dbl>
#> 1     1     2
#> 2     2     4
#> 3     3     8

# but this doesn't
df %>%
  mutate(!!col_name := if_else((!!col_name == 6 & a == 3), 8, !!col_name))
#> Error: Problem with `mutate()` input `b`.
#> x `false` must be a double vector, not a character vector.
#> i Input `b` is `if_else(("b" == 6 & a == 3), 8, "b")`.
Created on 2020-10-13 by the reprex package (v0.3.0)
2

There are 2 best solutions below

2
On BEST ANSWER

To use !! on RHS you need to first convert col_name to symbol.

library(dplyr)
df %>% mutate(!!col_name := if_else(!!sym(col_name) == 6 & a == 3, 
                            8, !!sym(col_name)))

Other alternatives include using get :

df %>% mutate(!!col_name := if_else(get(col_name) == 6 & a == 3,
                             8, get(col_name)))

Or without any NSE use .data :

df %>% mutate(!!col_name := if_else(.data[[col_name]] == 6 & a == 3, 
                            8, .data[[col_name]]))
0
On

Using base:

df[ df[, col_name ] == 6 & df$a == 3, col_name ] <- 8

df
#   a b
# 1 1 2
# 2 2 4
# 3 3 8

Note: Yes, I am aware that the question is about "tidy", this is just to illustrate why for some simple tasks base solutions are just as good/better.