2

tl;dr -- is it possible to use dplyr syntax to apply more than one function to a selection of variables in a single call to mutate(across(...)), without creating extra variables?

By way of example, say we want to apply mean and factor to mpg and cyl. We can do this by repeating ourselves:

library(dplyr)

# desired output (but we repeat ourselves)
mtcars %>%
    mutate(
        across(c('mpg', 'cyl'),
            mean
        )
    ) %>%
    mutate(
        across(c('mpg', 'cyl'),
            factor
        )
    )

I want to avoid repeating the mutate(across(...)) selection.

According to the reference for across, we can supply multiple functions or purrr-style lambdas in a list. However, I can't figure out how to mutate in place (overwrite the variable), rather than creating new variables.

Of course, applying a single function at a time does not create new variables with default parameters:

# single mean function mutates in place
mtcars %>%
    mutate(
        across(c('mpg', 'cyl'),
            ~mean(.)    
        )
    )

# single factor function mutates in place
mtcars %>%
    mutate(
        across(c('mpg', 'cyl'),
            ~factor(.)    
        )
    ) %>%
    glimpse()

But passing in a list creates new variables:

# this creates new vars
mtcars %>%
    mutate(
        across(c('mpg', 'cyl'),
            .fns = list(
                mean, factor
            )    
        )
    )

# as does this
mtcars %>%
    mutate(
        across(c('mpg', 'cyl'),
            .fns = list(
                ~mean(.), ~factor(.)
            )    
        )
    )

I've tried to specify the variable names directly with .names, but this does not work:

# trying to specify that we want to preserve
# the original names with {col} leads to a
# duplicated names error
mtcars %>%
    mutate(
        across(c('mpg', 'cyl'),
            .fns = list(
                mean, factor
            ),
            .names = "{col}"
        )
    )

# the same occurs with purrr-style lambda syntax
mtcars %>%
    mutate(
        across(c('mpg', 'cyl'),
            .fns = list(
                ~mean(.), ~factor(.)
            ),
            .names = "{col}"
        )
    )

Is this possible in a single mutate(across(...)) call?

heds1
  • 3,203
  • 2
  • 17
  • 32

1 Answers1

1

So you want to first take mean of those variables and then turn them into factor?

This can be achieved by :

library(dplyr)

mtcars %>% mutate(across(c('mpg', 'cyl'),~factor(mean(.)))) 
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
  • Haha! I think I had convinced myself that the solution would involve tricky syntax, and didn't even consider the simplest and most obvious method. Thanks Ronak. – heds1 Oct 28 '20 at 01:43