Creating new columns with mutate() and across()

Viewed 83

This is a simplified version of the actual problem I'm dealing with. In this example, I'll be working with four columns, and the actual problem requires working with about 20-30 columns.

Consider the iris dataset. Suppose that I wanted to, for some reason, append new columns which would be equal to double the .Length and the .Width columns. With the following code, this would change the existing columns:

library(dplyr)
head(iris)
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa
4          4.6         3.1          1.5         0.2  setosa
5          5.0         3.6          1.4         0.2  setosa
6          5.4         3.9          1.7         0.4  setosa

df_iris <- iris %>% mutate(across(matches("(\\.)(Length|Width)"), 
                                  function(x) { x * 2 }))
head(df_iris)

  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1         10.2         7.0          2.8         0.4  setosa
2          9.8         6.0          2.8         0.4  setosa
3          9.4         6.4          2.6         0.4  setosa
4          9.2         6.2          3.0         0.4  setosa
5         10.0         7.2          2.8         0.4  setosa
6         10.8         7.8          3.4         0.8  setosa

However, instead, I would like to have this doubled calculation create NEW columns, say .Length.2 and .Width.2. One way this could be done is the following:

double <- function(x) {
  x * 2
}

df_iris <- iris %>%
  mutate(Sepal.Length.2 = double(Sepal.Length),
         Sepal.Width.2 = double(Sepal.Width),
         Petal.Length.2 = double(Petal.Length),
         Petal.Width.2 = double(Petal.Width))

head(df_iris)

  Sepal.Length Sepal.Width Petal.Length Petal.Width Species Sepal.Length.2 Sepal.Width.2 Petal.Length.2 Petal.Width.2
1          5.1         3.5          1.4         0.2  setosa           10.2           7.0            2.8           0.4
2          4.9         3.0          1.4         0.2  setosa            9.8           6.0            2.8           0.4
3          4.7         3.2          1.3         0.2  setosa            9.4           6.4            2.6           0.4
4          4.6         3.1          1.5         0.2  setosa            9.2           6.2            3.0           0.4
5          5.0         3.6          1.4         0.2  setosa           10.0           7.2            2.8           0.4
6          5.4         3.9          1.7         0.4  setosa           10.8           7.8            3.4           0.8

Is there a way to do this in dplyr without:

  1. relying on superseded/deprecated functions?
  2. having to manually specify each column name?
1 Answers

We can use across (used dplyr 1.0.6 version)

library(dplyr)
df_iris <- iris %>%
    mutate(across(where(is.numeric), double, .names = '{.col}.2'))

-output

head(df_iris, 3)
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species Sepal.Length.2 Sepal.Width.2 Petal.Length.2 Petal.Width.2
1          5.1         3.5          1.4         0.2  setosa           10.2           7.0            2.8           0.4
2          4.9         3.0          1.4         0.2  setosa            9.8           6.0            2.8           0.4
3          4.7         3.2          1.3         0.2  setosa            9.4           6.4            2.6           0.4
Related