user63230
user63230

Reputation: 4708

R mutate new columns based on previous ones and dynamically name them

This is not the same question as this but an extension. What is the quickest way to generate multiple variables based on ones that you have created in mutate and dynamically name them. E.g.

library(dplyr)  
df<- data.frame(gg = rep(6:10),
                ba = rep(1:5))
df
  gg ba
1  6  1
2  7  2
3  8  3
4  9  4
5 10  5

desired output:

df_new
  gg ba diff.1 diff.2 sum_dif.1 sum_dif.2
1  6  1      5     10        25        50
2  7  2      5     10        25        50
3  8  3      5     10        25        50
4  9  4      5     10        25        50
5 10  5      5     10        25        50

Following the similar question I referenced I can get diff.1 diff.2

myfun <- function(df, n) {
  varname <- paste("diff", n , sep=".")
  mutate(df, !!varname := (gg - ba)*n)
}

for(i in 1:2) {
  df <- myfun(df, n=i)
}

which gives

df
  gg ba diff.1 diff.2
1  6  1      5     10
2  7  2      5     10
3  8  3      5     10
4  9  4      5     10
5 10  5      5     10

But not sure how to pass the generated variable to another line within mutate, I thought something like this:

myfun <- function(df, n) {
  varname <- paste("diff", n , sep=".")
  varname2 <- paste("sum_dif", n , sep=".")
  mutate(df, !!varname := (gg - ba)*n,
             !!varname2 := sum(!!varname))
}

Also happy to get any other solutions, maybe data.table? Thanks

Upvotes: 2

Views: 203

Answers (1)

akrun
akrun

Reputation: 887951

We need to convert the string to symbol before doing the evaluation (!!)

myfun <- function(df, n) {
 varname <- paste("diff", n , sep=".")
 varname2 <- paste("sum_dif", n , sep=".")
 mutate(df, !!varname := (gg - ba)*n,
         !!varname2 := sum(!! rlang::sym(varname)))
}

Now, we apply the myfun

for(i in 1:2) {
  df <- myfun(df, n=i)
 }

 df %>%
    select(gg, ba, matches('^diff'), matches('^sum'))
#   gg ba diff.1 diff.2 sum_dif.1 sum_dif.2
#1  6  1      5     10        25        50
#2  7  2      5     10        25        50
#3  8  3      5     10        25        50
#4  9  4      5     10        25        50
#5 10  5      5     10        25        50

Upvotes: 2

Related Questions