【问题标题】:How to apply the same functions to multiple data frames to overwrite input variables using assign(deparse(substitute(df)))? [R]如何将相同的函数应用于多个数据帧以使用assign(deparse(substitute(df)))覆盖输入变量? [R]
【发布时间】:2018-08-20 06:12:22
【问题描述】:

我有多个列数相同的数据框。

iris1 <- iris
iris2 <- iris

然后,我想提取一些特定的列,并用具有特定列的列覆盖原始数据帧。

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

如果我只将函数应用于一个数据帧,效果会很好:

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 ...

但是,一旦我尝试将其应用于多个数据帧,它就不起作用了:

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

我试图找到解决方案,但大多数建议建议使用lapply,它以列表格式返回结果。

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

我只想通过函数覆盖数据帧iris1iris2,但是如何?目前我正在按数据帧运行函数,但我希望在一次操作中完成。

func(iris1)
func(iris2)

【问题讨论】:

  • 当您使用lapply() 时,每个单独的函数调用都具有此签名:FUN(X[[i]], ...)(即deparse(substitute(df)) == "X[[i]]")。所以任何替代方法都会失败。我认为您只需将要分配的名称作为参数传递给func()
  • 谢谢。我尝试了以下脚本,但出现了错误。 assign(paste(df,"",sep=""),temp,envir=.GlobalEnv)(instead of original operation in the function)lapply(list(iris1,iris2)extr)Error:list(iris1,iris2) is not function,string or symbol

标签: r lapply


【解决方案1】:

试试这个:

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 ...

【讨论】:

    【解决方案2】:

    一种方法是使用evalparsepaste0 在for 循环中运行命令。这可行,但并不理想。

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

    这会循环遍历名称列表并为每个名称运行一个命令,因此列表 c("iris1", "iris2") 将运行:

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

    【讨论】:

    • 感谢您的建议。它成功了,但将它应用到实际数据框有点困难,因为我需要为它们指定一些参数。
    猜你喜欢
    • 2020-02-25
    • 2015-06-16
    • 1970-01-01
    • 2017-04-26
    • 2016-12-25
    • 1970-01-01
    • 2019-05-21
    • 2020-07-11
    • 1970-01-01
    相关资源
    最近更新 更多