简体   繁体   中英

How to apply the same functions to multiple data frames to overwrite input variables using assign(deparse(substitute(df)))? [R]

I have multiple data frames which have the same number of columns.

iris1 <- iris
iris2 <- iris

Then, I want to extract some specific columns and overwrite original data frames by the ones with specific columns.

func <- function(df) {
    temp <- df %>%
    select("Species",starts_with("Sepal"))
    assign(deparse(substitute(df)),temp,envir=.GlobalEnv)
    }

It works well if I apply the function to only one data frame:

func(iris1)

str(iris1)
'data.frame':   150 obs. of  3 variables:
 $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
 $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...

However, once I try to apply it to multiple data frames, it does not work:

func(list(iris1,iris2))
Error: Variable context not set

I tried to find solutions but most of suggestions recommend to use lapply which returns the result in list format.

lapply(list(iris1,iris2),func) -> result

I just want to overwrite data frames iris1 and iris2 by the function but how?Currently I am running the function by data frame but I wish to do it in one operation.

func(iris1)
func(iris2)

Try this:

func <- function(...) {
  require(dplyr)
  mc <- match.call(expand.dots = FALSE)
  lapply(mc$..., function(n) {
    assign(deparse(n), get(deparse(n)) %>% select("Species",starts_with("Sepal")), envir = .GlobalEnv)
  })
  invisible()
}

> str(iris1)
'data.frame':   150 obs. of  5 variables:
 $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
 $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
 $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
 $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
 $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
> str(iris2)
'data.frame':   150 obs. of  5 variables:
 $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
 $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
 $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
 $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
 $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
> func(iris1, iris2)
> str(iris1)
'data.frame':   150 obs. of  3 variables:
 $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
 $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
> str(iris2)
'data.frame':   150 obs. of  3 variables:
 $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
 $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
 $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...

One way is to use eval , parse and paste0 to run commands inside a for loop. This works, but isn't ideal.

for (df in c("iris1", "iris2")) {
  eval(parse(text = paste0(df, ' <- select(', df ,', "Species", starts_with("Sepal"))')))
}

This loops though the list of names and runs a command for each of them, so the list c("iris1", "iris2") will run:

iris1 <- select(iris1, "Species", starts_with("Sepal"))
iris2 <- select(iris2, "Species", starts_with("Sepal"))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM