tidyr use glue strings later in function

Tidy eval now supports glue strings

So this works great:

my_summarise5 <- function(data, mean_var ) { data %>% mutate( "mean_{{mean_var}}" := mean({{ mean_var }}), )
}
mtcars %>% my_summarise5(cyl)

But then

my_summarise5 <- function(data, mean_var ) { data %>% mutate( "mean_{{mean_var}}" := mean({{ mean_var }}), "mean_{{mean_var}}_plusone" := "mean_{{mean_var}}"+1 )
}
mtcars %>% my_summarise5(cyl)

Throws

Error: Problem with `mutate()` input `mean_cyl_plusone`.
x non-numeric argument to binary

Would some 'paste' or 'glue' thing in the "mean_{{mean_var}}_plusone" := "mean_{{mean_var}}"+1 part fix this?

Note this is obviously not a useful case, its a MWE for the syntax. I actually want to define two new columns with different names, one which uses the other ... otherwise I have to repeat and it also gets messy.

2 Answers

Use across:

my_summarise5 <- function(data, mean_var ) { data %>% mutate( "mean_{{mean_var}}" := mean({{ mean_var }}), across(last_col(), ~.+1, .names = "{col}_plusone") )
}
mtcars %>% my_summarise5(cyl) %>% head

giving:

 mpg cyl disp hp drat wt qsec vs am gear carb mean_cyl mean_cyl_plusone
Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 6.1875 7.1875
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 6.1875 7.1875
Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 6.1875 7.1875
Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1 6.1875 7.1875
Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2 6.1875 7.1875
Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1 6.1875 7.1875
1

I love the tidyverse, but using base R can have a big payoff, by making your code readable and maintainable.

my_summarise5 <- function (data, mean_var) { mean_name <- paste0("mean_", mean_var) plus_one_name <- paste0(mean_name, "_plus_one") data[[mean_name]] <- mean(data[[mean_var]]) data[[plus_one_name]] <- data[[mean_name]] + 1 data
}

Anybody who knows R can understand the above.

tmp <- data.frame(a = 1:5)
my_summarise5(tmp, "a")
## a mean_a mean_a_plus_one
## 1 1 3 4
## 2 2 3 4
## 3 3 3 4
## 4 4 3 4
## 5 5 3 4

If you want to pass a bare symbol as mean_var, then just add this line to the start of the function:

mean_var <- as.character(substitute(mean_var))

This isn't perfect, because it'll break with deeply nested functions. So you could mix a little tidyverse in by doing (something like) mean_var <- enquo(mean_var). But I still would prefer the simple data manipulation to stuff with mutate and across.

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

You Might Also Like