Paste variable names inside mutate(across())

Viewed 264

I am trying to set variable values that are NA in several columns to the values in different but similarly-named columns. I was wondering if this is possible using dplyr.

As an example, suppose I have the following data frame:

x <- tribble(~x_var1, ~x_var2, ~y_var1, ~y_var2,
             5, 2, 0, 0,
             NA, 10, 8, 0,
             3, NA, 0, 5,
             NA, NA, 7, 9)    

and I want to replace NA values in x_var1 and x_var2 with the corresponding values in y_var1 and y_var2. My dataset has more than two such columns so I was wondering whether there is a neat way to do this with mutate(across(...)) or other dplyr operations.

My attempt is to do as follows:

x %>% 
  mutate(across(c(x_var1, x_var2),
         ~ ifelse(is.na(.), paste0("y_", str_remove(., "x_")), .))) # if NA replace with y_(varname)

But of course this doesn't work because the paste and str_remove functions are not operating on the variable name.

Thanks in advance!

(Edit: I suppose I could use pivot_longer / pivot_wider but I'm curious whether there are alternative solutions.)

1 Answers

I think the approach you posted in your comment is ok. We could simplify it a bit:

library(dplyr)

x <- tribble(~x_var1, ~x_var2, ~y_var1, ~y_var2,
             5, 2, 0, 0,
             NA, 10, 8, 0,
             3, NA, 0, 5,
             NA, NA, 7, 9)   

x %>%
  mutate(across(c(x_var1, x_var2),
                ~ ifelse(is.na(.),
                         get(gsub("^x_", "y_", cur_column())),
                         .))) 
#> # A tibble: 4 x 4
#>   x_var1 x_var2 y_var1 y_var2
#>    <dbl>  <dbl>  <dbl>  <dbl>
#> 1      5      2      0      0
#> 2      8     10      8      0
#> 3      3      5      0      5
#> 4      7      9      7      9

Created on 2021-02-18 by the reprex package (v0.3.0)

Another approach in the larger tidyverse would be to use purrr::reduce in combination with a custom function.

my_replace_na <- function(df, x) {
  mutate(df, !! x := ifelse(is.na(!!sym(x)),
                            !!sym(gsub("^x_", "y_", x)),
                            !!sym(x)))
}

x %>% 
  purrr::reduce(c("x_var1", "x_var2"), my_replace_na, .init = .)
Related