【问题标题】:Is there a way in r to use a character list of object names to mutate these objects with base::lapply and dplyr::mutater 中有没有办法使用对象名称的字符列表来使用 base::lapply 和 dplyr::mutate 来改变这些对象
【发布时间】:2020-11-27 17:00:30
【问题描述】:

我对这个话题很陌生,可能无法用正确的方式表达自己。我想要做的是对我工作区中的几个对象执行相同的操作。

因此,我生成了这些对象的列表,并尝试将此列表提供给 lapply,后者随后将其提供给 mutate。其中一列应包含类型(例如“Experiment”或“exp”),另一列应包含相应对象的名称(例如“iris2”)。使用 mutate(iris2, type = "exp", name = "iris2") 实现了所需的结果,但是当我尝试将列表输入构造时出现错误。我搜索了两天,但找不到有效的解决方案。示例代码如下。

感谢您对此的任何帮助, 斯蒂芬

library(dplyr)

iris2 <- iris
iris4 <- iris

mutate(iris2, type = "exp", name = "iris2")

file_list <- list("iris2", "iris4")

my_fun <- function(x) { 
  as.name(x) %>%       
    mutate(type = "exp", name = as.character(x))
}

result <- file_list %>% lapply( my_fun )

【问题讨论】:

    标签: r lapply dplyr


    【解决方案1】:

    这里的问题是您传递了一个字符串,该字符串表示您希望使用的数据框的名称。当您在函数中调用 as.name(x) 时,您实际上是在将符号作为参数传递给 mutate,而不是该符号所引用的数据框。如果你想访问一个符号所指的对象,你需要eval那个符号,所以你可以使用eval(as.name(x))

    但是,R 中从符号名称获取对象的快捷方式是get(x),相当于eval(as.name(x))

    my_fun <- function(x) mutate(get(x), type = "exp", name = as.character(x))
    
    result <- lapply(file_list, my_fun)
    

    如果我们查看result 中两个数据帧的head,我们可以看到预期的结果:

    lapply(result, head)
    #> [[1]]
    #>   Sepal.Length Sepal.Width Petal.Length Petal.Width Species type  name
    #> 1          5.1         3.5          1.4         0.2  setosa  exp iris2
    #> 2          4.9         3.0          1.4         0.2  setosa  exp iris2
    #> 3          4.7         3.2          1.3         0.2  setosa  exp iris2
    #> 4          4.6         3.1          1.5         0.2  setosa  exp iris2
    #> 5          5.0         3.6          1.4         0.2  setosa  exp iris2
    #> 6          5.4         3.9          1.7         0.4  setosa  exp iris2
    #> 
    #> [[2]]
    #>   Sepal.Length Sepal.Width Petal.Length Petal.Width Species type  name
    #> 1          5.1         3.5          1.4         0.2  setosa  exp iris4
    #> 2          4.9         3.0          1.4         0.2  setosa  exp iris4
    #> 3          4.7         3.2          1.3         0.2  setosa  exp iris4
    #> 4          4.6         3.1          1.5         0.2  setosa  exp iris4
    #> 5          5.0         3.6          1.4         0.2  setosa  exp iris4
    #> 6          5.4         3.9          1.7         0.4  setosa  exp iris4
    

    请注意,如果您将多个相似的对象放在一个列表中,则不需要这样做。起初将数据框放在列表中感觉有点陌生,但是当您必须跨多个数据框执行操作时,它会变得容易得多。例如,您可以这样做:

    iris_list <- list(iris2 = iris, iris4 = iris)
    

    您可以使用iris_list[[1]]iris_list[[2]] 等轻松访问每个数据帧,这不会增加很多击键。您还可以摆脱对file_list 和单独函数的需求,因为您可以在一行中实现所有内容:

    Map(function(x, y) mutate(x, type = "exp", name = y), iris_list, names(iris_list))
    

    如果在任何时候,您希望数据帧回到您的全局环境中,您可以这样做list2env(iris_list, globalenv())

    【讨论】:

    • 非常感谢!这正是我想要的。有没有办法做到这一点并覆盖原始数据帧。这意味着我保留单独的变异数据帧?
    • @Stephan 是的,你可以,但我不推荐它。您应该习惯使用列表中的多个数据框,特别是如果您要对它们执行相同的操作。请参阅我的更新,展示如何更轻松地处理列表中的数据框,以及如果您确实需要如何将它们放入全局环境中。
    • 再次感谢艾伦。这让我已经花了两天时间独自尝试,但收效甚微,现在看起来很容易;)你让我开心!
    • 如果我想操作列表中数据框的元素,我还有一个问题。例如,我在列表中有几个包含相同列的数据框,但某些观察列并未出现在所有数据框中。我可以比较列表中的这些数据框并将它们存储为新的数据框列表,其中仅包含所有数据框中存在的列吗?
    【解决方案2】:

    我们可以从purrr使用map

    library(purrr)
    library(dplyr)
    map(file_list, ~ get(.x) %>% 
              mutate(type = "exp", name = .x) )
    

    【讨论】:

    • 感谢 akrun,这是它应该做的,但我不完全理解 ~get(.x) 术语。您能否解释一下该功能的作用。我使用了它的帮助,但我并不完全理解它。
    • @Stephan file_list 是在全局环境中创建的字符串形式的对象名称列表,get 从全局环境中返回该对象的值,然后我们 mutate on该对象带有一个新列。 map 的输出是 list,但它不会更新原始对象。如果您需要更新它,您可能需要在名为 list 的输出上使用 list2env
    • 非常感谢您的解释。
    猜你喜欢
    • 2013-02-19
    • 1970-01-01
    • 2021-11-22
    • 1970-01-01
    • 1970-01-01
    • 2019-08-24
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    相关资源
    最近更新 更多