【问题标题】:Using rbind() to combine multiple data frames into one larger data.frame within lapply()在 lapply() 中使用 rbind() 将多个数据帧组合成一个更大的 data.frame
【发布时间】:2016-08-22 12:26:04
【问题描述】:

我正在使用 R-Studio 0.99.491 和 R 版本 3.2.3 (2015-12-10)。我是 R 的相对新手,我会很感激一些帮助。我正在做一个项目,我试图在旧媒体服务器上使用服务器日志来识别服务器中的哪些文件夹/文件仍在被访问,哪些不是,以便我的团队知道要迁移哪些文件。每个日志都是 24 小时的,而我有大约一年的日志,所以理论上,我应该能够看到过去一年的所有访问。

我的理想输出是获得一个树形结构或绘图,它将向我显示我们服务器上正在使用的文件夹。我已经想出了如何将一个日志(一天)作为 data.frame 读入 R,然后使用 R 中的 data.tree 包将其变成一棵树。现在,我想在创建树之前,一个一个地递归地遍历目录中的所有文件,并将它们添加到原始 data.frame 中。这是我当前的代码:

#Create the list of log files in the folder
files <- list.files(pattern = "*.log", full.names = TRUE, recursive = FALSE)
#Create a new data.frame to hold the aggregated log data
uridata <- data.frame()
#My function to go through each file, one by one, and add it to the 'uridata' df, above
lapply(files, function(x){
    uriraw <- read.table(x, skip = 3, header = TRUE, stringsAsFactors = FALSE)
    #print(nrow(uriraw)
    uridata <- rbind(uridata, uriraw)
    #print(nrow(uridata))
})

问题是,无论我尝试什么,lapply 循环中的 'uridata' 的值似乎都没有在 lapply 循环之外保存/传递,但每次循环运行时都会以某种方式被覆盖。所以我没有得到一个大的data.frame,而是得到最后一个'uriraw'文件的内容。 (这就是为什么循环中有这两个注释打印命令的原因;我正在测试每次循环运行时数据帧中有多少行。)

谁能澄清我做错了什么?同样,我希望最后有一个大的 data.frame,它结合了文件夹中每个(当前七个)日志文件的内容。

【问题讨论】:

  • herehere 可能有用
  • uridata 保持不变,因为函数在 R 中没有副作用,这是函数式编程最重要的特性之一。正如@rawr 指出的那样,您可以改为do.call("rbind", lapply(files, read.table, skip = 3, header = T, stringsAsFactors = F)) 做这样的事情。或者,如果您将您的 lapply 函数替换为 for loop,您的代码将起作用。
  • *apply 函数中创建的变量的作用域是该函数,除非您使用&lt;&lt;-,通常不建议这样做。通常的策略是使用lapplylist of data.frameslist_of_data.frames &lt;- lapply(files, function(x){read.table(x, skip = 3, header = TRUE, stringsAsFactors = FALSE)}) 类似,然后将它们与do.call(rbind, list_of_data.frames) 组合成一个单独的data.frame。

标签: r dataframe lapply read.table rbind


【解决方案1】:

do.call() 是你的朋友。

big.list.of.data.frames <- lapply(files, function(x){
    read.table(x, skip = 3, header = TRUE, stringsAsFactors = FALSE)
})

或更简洁(但不太容易修改):

big.list.of.data.frames <- lapply(files, read.table, 
                                  skip = 3,header = TRUE,
                                  stringsAsFactors = FALSE)

然后:

big.data.frame <- do.call(rbind,big.list.of.data.frames)

这是一种推荐的做事方式,因为在 R 中动态地“增长”数据框是很痛苦的。速度慢且占用内存,因为每次迭代都会构建一个新框架。

【讨论】:

  • 这完美解决了问题。当然,我应该在函数的开头将 lapply() 的结果传递到变量中,而不是尝试将它们保存到 lapply() 中的变量中。感谢您将我指向 do.call()。
【解决方案2】:

您可以使用purrr 包中的map_df 代替lapply,直接将所有结果合并为一个数据框。

map_df(files, read.table, skip = 3, header = TRUE, stringsAsFactors = FALSE)

【讨论】:

    【解决方案3】:

    另一个选项是fread 来自data.table

    library(data.table)
    rbindlist(lapply(files, fread, skip=3))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-04-04
      • 1970-01-01
      • 1970-01-01
      • 2015-05-13
      • 1970-01-01
      • 2023-03-20
      • 1970-01-01
      相关资源
      最近更新 更多