【问题标题】:How To Create R Data Frame From List In Loop如何从循环列表中创建 R 数据框
【发布时间】:2018-08-28 13:46:09
【问题描述】:

我在从 R 中的循环返回数据帧时遇到问题。我有一组函数可以读取文件并将它们转换为数据帧以供更大的项目使用/可视化。

我有一个要传递的文件名列表:

# list of files to read
frameList <-c("apples", "bananas", "pears")

此函数遍历列表并运行函数以创建数据框(如果它们尚不存在)。

populateFrames <- function(){
    for (frame in frameList){
        if (exists(frame) && is.data.frame(get(frame))){
            # do nothing
        }
        else {
            frame <- clean_data(gather_data(frame))
        }
    }
}

执行时,函数运行时没有错误,但不会将任何数据帧保存到环境中。

我可以手动运行同样的东西并保存一个数据框:

# manually create "apples" data frame
apples <- clean_data(gather_data(frameList[1]))

通过阅读此处的类似问题,我发现 assign() 用于类似的事情。但是和以前一样,我可以很好地手动运行代码;但是当放在循环中时,没有数据框被保存到环境中。

# returns a data frame, "apples" to the environment 
assign(x = frame[1], value = clean_data(gather_data(frame[1])))

【问题讨论】:

  • 您的问题是您正在函数的本地范围内创建数据框,并且当您的程序离开该范围时,您的数据不会被保存。尝试在函数外部运行 for 循环。
  • 在 R 术语中,c("apples", "bananas", "pears") 是一个字符向量,而不是一个列表。这是一个重要的区别,因为解决方案可能会因所涉及的对象类型而异。

标签: r for-loop dataframe


【解决方案1】:

解决方案,遵循“尽可能少改变 OPs 实现”的原则。

这里有两个问题。

  1. 您的函数没有返回任何内容,因此发生的任何更改都停留在函数的环境中
  2. 我认为您期望在elsestatement 中重新分配frame 以将其重新分配给frameList 中的该元素。不是。

这是在函数的父环境中分配变量的不推荐*方法。在这种情况下,您将 populatingFrames 作为副作用,在父环境中改变 frameList。如果您想练习防御性编程,通常要避免改变输入。

populateFrames <- function(){
    for (i in seq_along(frameList)){
        if (exists(frameList[[i]]) && is.data.frame(get(frameList[[i]]))){
            # do nothing
        }
        else {
            frameList[[i]] <<- clean_data(gather_data(frameList[[i]]))
        }
    }
}

这是您返回新 frameList 的推荐版本(这意味着您必须为其分配一个值)。

populateFrames <- function(){
    for (i in seq_along(frameList)){
        if (exists(frameList[[i]]) && is.data.frame(get(frameList[[i]]))){
            # do nothing
        }
        else {
            frameList[[i]] <- clean_data(gather_data(frameList[[i]]))
        }
    }
    frameList
}

【讨论】:

  • frame &lt;&lt;- 将分配给一个名为“frame”的对象,对吧?
  • OP 可能想要使用 assign 和 envir = .GlobalEnv
  • frame &lt;&lt;- 将在父环境中查找frame,并使用正确的操作数(此处为clean_data(gather_data(frame)))对其进行更新。如果它在父环境中不存在,它会继续向上移动搜索树,直到找到frame,或者到达.GlobalEnv,然后将它设置在那里
  • 如果这个函数不打算用作包的一部分,或者在其他环境结构中,这将按预期工作。否则,@WalkerintheCity 的建议将是首选。
  • 是的,这里的用例在包之外。只是一个简单的闪亮应用程序,可以从用户保存的文件中加载数据。 @WalkerintheCity 的建议似乎正是我所需要的。
【解决方案2】:

避免全局变量赋值,这通常是一个禁忌,尝试 lapply:

lapply(
  frameList,
  function(frame){
    if(exists(frame) && is.data.frame(get(frame))){
      frame
    }else{
      clean_data(gather_data(frame))
    }
  }
)

【讨论】:

  • 这将生成一个表列表,您可以将其与 rbindlist 或您拥有的任何东西放在一起。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-31
  • 1970-01-01
  • 1970-01-01
  • 2019-08-26
  • 2020-09-19
  • 1970-01-01
相关资源
最近更新 更多