Home > other >  Pass character string of column names (e.g. "c(speed, dist") to `across` function in R
Pass character string of column names (e.g. "c(speed, dist") to `across` function in R

Time:10-26

Consider the following toy problem. I would like to round drat and wt. Here is the normal way to do this:

library(tidyverse)
mtcars[1 ,5:7] %>% 
  mutate(across(.cols = c(drat, wt), .fns = round))
#>           drat wt  qsec
#> Mazda RX4    4  3 16.46

But what I want to do is select drat and wt from the data. Like below (doesn’t run). How might I do this?

mtcars_2 <- 
  mtcars[1 ,5:7] %>%
  bind_cols(data.frame(cols_to_modify = "c(drat, wt)"))

## view data
mtcars_2
#>           drat   wt  qsec cols_to_modify
#> Mazda RX4  3.9 2.62 16.46    c(drat, wt)

## my failed attempt
mtcars_2 %>% 
  mutate(across(.cols = eval(substitute(.$cols)),.fns = round))
#> Error: Problem with `mutate()` input `..1`.
#> ℹ `..1 = across(.cols = eval(substitute(.$cols)), .fns = round)`.
#> x Can't subset columns that don't exist.
#> x Column `c(drat, wt)` doesn't exist.

Created on 2021-10-25 by the reprex package (v2.0.1)

CodePudding user response:

You can't use substitute() or eval() on character vectors. You need to parse those character vectors into language objects. Otherwise when you eval a string, you just get that string back. It's not like eval in other languages. One way to do the parsing is str2lang. Then you can inject that expression into the across using tidy evaulation's !!. For example

mtcars_2 %>% 
  mutate(across(.cols = !!str2lang(.$cols_to_modify),.fns = round))
  • Related