Home > Blockchain >  R function create custom variable name
R function create custom variable name

Time:11-01

I have written a function to calculate the mean values from monthly data within a year (starting in the previous Dec to the current Sep). Each dataframe (and there are many) that I'm feeding through this function is presently named for the variable that I'm interested in. But I want the output to use the name of the dataframe as the variable.

Example:

year <- c(2000:2020)
`1` <- runif(21, 0,10)
`2` <- runif(21, 0,10)
`3` <- runif(21, 0,10)
`4` <- runif(21, 0,10)
`5` <- runif(21, 0,10)
`6` <- runif(21, 0,10)
`7` <- runif(21, 0,10)
`8` <- runif(21, 0,10)
`9` <- runif(21, 0,10)
`10` <- runif(21, 0,10)
`11` <- runif(21, 0,10)
`12` <- runif(21, 0,10)
dogs <- as.data.frame(cbind(year, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`, `10`, `11`, `12`))

fun_annual <- function(df) { 
  name = deparse(substitute(df)) #I know I can use this to get the name of the dataframe
  df %>% 
  mutate(lag12 = lag(`12`)) %>% 
  rowwise() %>% # complete next calculations row by row
  mutate(name = mean(c_across(c(`1`:`9`, lag12)))) %>% #mean from prev Dec to Sep
  select(year, name) #by this point 'name' should be 'dogs' (name of original dataframe
}
# Final function should return a dataframe with 2 variables: year and dogs

Bonus points if someone can also help be figure out how to put the months in the function, so I don't have to change the months within the function each time! Especially if I use more months from the previous year (beyond Dec)

CodePudding user response:

Based on Pass a string as variable name in dplyr::mutate, you can use rlang's !!, sym(), and :=.

sym takes the value from name and turn it into a symbol. !! makes sure that sym takes effect before R evaluate the code. And, as there is no sym()<- function, we can't use = to modify the left hand side, and need to use the glue package syntax with :=.

Also, you can use dplyr::all_of to get the columns for the months.

fun_annual <- function(df, months) { 
  name = deparse(substitute(df))
  df %>% 
    mutate(lag12 = lag(`12`)) %>% 
    rowwise() %>%
    mutate(!!sym(name) := mean(c_across(c(all_of(months), lag12)))) %>%
    select(year, !!sym(name))
}

> fun_annual(dogs, paste(1:9))
# A tibble: 21 × 2
# Rowwise: 
year  dogs
<dbl> <dbl>
  1  2000 NA   
2  2001  4.33
3  2002  5.67
4  2003  3.68
5  2004  4.07
6  2005  5.52
7  2006  5.98
8  2007  6.34
9  2008  6.18
10  2009  3.66
# … with 11 more rows

CodePudding user response:

Similar, but slightly different:

library(tidyverse)

fun_annual  <- function(df) {
  name <- quo_name(enquo(df))
  
  df |>
    mutate(lag12 = lag(`12`)) |>
    rowwise() |>
    mutate("{name}" := mean(c_across(c(`1`:`9`, lag12)))) |>
    select(year, !!name)
    
}

fun_annual(dogs)
#> # A tibble: 21 x 2
#> # Rowwise: 
#>     year  dogs
#>    <dbl> <dbl>
#>  1  2000 NA   
#>  2  2001  5.58
#>  3  2002  5.72
#>  4  2003  3.89
#>  5  2004  4.77
#>  6  2005  3.98
#>  7  2006  5.98
#>  8  2007  4.61
#>  9  2008  5.23
#> 10  2009  5.91
#> # ... with 11 more rows

EDIT

bonus for months:


fun_annual  <- function(df, months) {
  name <- quo_name(enquo(df))
  
  df |>
    mutate(lag12 = lag(`12`)) |>
    rowwise() |>
    mutate("{name}" := mean(c_across(c({{months}}, lag12)))) |>
    select(year, !!name)
}

fun_annual(dogs, months = c(`1`, `2`))
#> # A tibble: 21 x 2
#> # Rowwise: 
#>     year  dogs
#>    <dbl> <dbl>
#>  1  2000 NA   
#>  2  2001  4.76
#>  3  2002  4.74
#>  4  2003  5.35
#>  5  2004  8.11
#>  6  2005  2.26
#>  7  2006  1.90
#>  8  2007  5.75
#>  9  2008  8.35
#> 10  2009  4.81
#> # ... with 11 more rows

fun_annual(dogs, months = c(`1`, `4`, `5`))
#> # A tibble: 21 x 2
#> # Rowwise: 
#>     year  dogs
#>    <dbl> <dbl>
#>  1  2000 NA   
#>  2  2001  3.76
#>  3  2002  5.92
#>  4  2003  3.66
#>  5  2004  5.78
#>  6  2005  4.67
#>  7  2006  3.53
#>  8  2007  5.31
#>  9  2008  7.15
#> 10  2009  5.02
#> # ... with 11 more rows
  • Related