2

I have a simple function in R to modify a dataframe

monthly_fun <- function(x){
x  %>% 
  mutate(obstime = convert_dates(obstime)) %>% 
  select(obstime, x = obsvalue)
}

When applying the function to dataframe df, i.e. monthly_fun(df), I would like df to be the name of obsvalue. In my current code, the name is obviously "x", how can I modify the part in select to get the name of the supplied dataframe as the variable name instead?

Thanks a lot

EDIT: I want to apply this function to several dataframes using

result <- list( df1, df2, df3) %>%
    lapply( monthly_fun )
user6441253
  • 123
  • 4

2 Answers2

2

You could extract the name of input by deparse(substitute(x)), and use !!y := obsvalue in mutate().

monthly_fun <- function(x) {
  y <- deparse(substitute(x))
  x  %>% 
    mutate(obstime = convert_dates(obstime),
           !!y := obsvalue) %>% 
    select(obstime, y)
}

A simplified example:

fun <- function(x) {
  y <- deparse(substitute(x))
  x  %>% 
    mutate(!!y := 1) %>% 
    select(y)
}

fun(df)

#       df
#  1     1
#  2     1
#  3     1
#  4     1
#  5     1

Update

If you want to apply it to several data frames stored in a list, you should design a 2-argument function, one argument for data and the other for new column names. Then use Map() to apply this function over each pair of data and names.

fun <- function(x, y) {
  x %>% 
    mutate(!!y := 1) %>% 
    select(y)
}

Map(fun, list(df1, df2), c("name1", "name2"))

# [[1]]
#     name1
# 1       1
# 2       1
# 3       1
# 4       1
# 5       1
#
# [[2]]
#     name2
# 1       1
# 2       1
# 3       1
# 4       1
# 5       1

If you're familiar with purrr, The use of Map can be replaced with map2() or imap(). (Notice the difference of inputs to the both functions)

library(purrr)

# (1) map2(): Input data and names separately
map2(list(df1, df2), c("name1", "name2"), fun)

# (2) imap(): Input a named list
imap(list(name1 = df1, name2 = df2), fun)
Darren Tsai
  • 32,117
  • 5
  • 21
  • 51
  • Thank you so much, it does work, but when I try to apply it to several dataframes, for instance if I create 2 dataframes iris1 and iris2: list( iris1, iris2) %>% lapply( monthly_fun ) it does not work anymore. Thanks again ! – user6441253 Jun 16 '22 at 11:57
  • @user6441253 See my update! Does it help? You can adjust the names as whatever you want. E.g. if you want the column names to be the same as the data names, just use `Map(fun, list(df1, df2), c("df1", "df2"))`. The name vector `c("df1", "df2")` can be automatically created by `paste()` or `ls(pattern = "input regex pattern here")` – Darren Tsai Jun 17 '22 at 01:49
  • Yes, thanks a lot and sorry for the delay ! – user6441253 Jun 20 '22 at 12:30
1

Using the suggestion by Julien and creating a variable using deparse(substitute(df)) and rename using that.

monthly_fun <- function(x) {
  y = deparse(substitute(x))
     x <- x %>% 
         mutate(obstime = obstime*5) %>%
         select(obstime, obsvalue)
     names(x)[names(x) == "obsvalue"] <- y
     return(x)
}

see this site for more naming methods.

Godrim
  • 449
  • 2
  • 10
  • Thanks a lot, it works. But I was imprecise in my question, see my comment to Darren Tsai's answer. I edited the question, thanks again ! – user6441253 Jun 16 '22 at 12:02