【问题标题】:Read huge csv file using `read.csv` by divide-and-conquer strategy?通过分治策略使用“read.csv”读取巨大的 csv 文件?
【发布时间】:2019-09-04 22:47:02
【问题描述】:

我应该在 R 中读取一个大的 csv 文件(5.4GB,7m 行和 205 列)。我已使用 data.table::fread() 成功读取它。但是我想知道是否可以使用基本的read.csv()来阅读它?

我尝试使用蛮力,但我的 16GB RAM 无法容纳。然后我尝试使用如下的“分而治之”(分块)策略,但它仍然不起作用。我该怎么做?

dt1 <- read.csv('./ss13hus.csv', header = FALSE, nrows = 721900, skip =1)
print(paste(1, 'th chunk completed'))
system.time(
  for (i in (1:9)){
    tmp = read.csv('./ss13hus.csv', header = FALSE, nrows = 721900, skip = i * 721900 + 1)
    dt1 <- rbind(dt1, tmp)
    print(paste(i + 1, 'th chunk completed'))
  }
)

我还想知道fread() 是如何工作的,它可以一次非常高效地读取所有数据,无论是在内存还是时间方面?

【问题讨论】:

  • 我认为问题不在于加载数据,我猜是持有数据。更不用说使用rbind 进行迭代构建总是一件坏事:每次添加anything 时,R 都会对先前的数据进行完整的复制。对于以前的版本,我更喜欢do.call(rbind.data.frame, lapply(fnames, read.csv)),但我不知道这会解决你的大数据问题。如果这不起作用,您可以考虑一次只处理一部分数据,将其聚合 (?),保存,然后继续下一批。
  • 是的,这叫做分块阅读。 但是,您的问题是由于没有为您的 205 列定义 colClasses 导致的内存膨胀(您真的需要阅读所有这些列吗?它会非常适合)
  • 是的,我需要读取所有数据。但是我怎样才能摆脱内存问题呢?
  • 为 205 列定义 colClasses,为整数列定义整数,为双列定义数字,为因子列定义因子。否则,事情的存储效率将非常低。请参阅?fread 和手册。

标签: r csv memory fread read.csv


【解决方案1】:

您的问题不是 fread(),而是由于没有为所有 (205) 列定义 colClasses 导致的内存膨胀。但请注意,尝试将所有 5.4GB 读入 16GB RAM 确实是在推动它,您几乎肯定无法将所有数据集保存在内存中;即使可以,每当您尝试处理它时,您都会炸毁内存。所以你的方法不会奏效,你必须决定你可以处理哪个子集 - 你绝对需要开始使用哪些字段

  • 为 205 列定义 colClasses:“integer”表示整数列,“numeric”表示双列,“logical”表示布尔列,“factor”表示因子列。否则存储的效率会很低(例如,数百万个字符串非常浪费),结果很容易比原始文件大 5-100 倍。

  • 如果您不能容纳所有 7m 行 x 205 列(您几乎肯定不能),那么您需要通过执行以下部分或全部操作来积极减少内存

    • 读入和处理块(行)(使用skip, nrows 参数,并在 SO 中搜索有关 fread in chunks 的问题)
    • 过滤掉所有不需要的行(例如,您可以进行一些粗略的处理以形成您关心的子集行的行索引,然后导入更小的集合)
    • 删除所有不需要的列(使用 fread select/drop 参数(指定要保留或删除的列名向量)。
  • 确保选项stringsAsFactors=FALSE,这是 R 中一个臭名昭著的糟糕默认设置,会导致无休止的记忆悲伤。

  • 日期/日期时间字段当前被读取为字符(这对内存使用来说是个坏消息,数百万个唯一字符串)。要么完全删除日期列作为开始,要么分块读取数据并使用fasttime 包或标准基本函数进行转换。
  • 查看用于 NA 处理的 args。现在,您可能希望删除包含大量 NA 的列或杂乱的未处理字符串字段。

请参阅?freaddata.table doc 了解上述语法。如果您遇到特定错误,请发布一条包含 2 行数据 (head(data)) 的 sn-p、您的代码和错误。

【讨论】:

  • 感谢您的回答!但您似乎误解了我的问题。我已经使用 fread() 成功加载了这个 5.4GB 文件(并且可用内存增加了 30% 以上),但是不适用于 R baisc 函数“read.csv”
  • 我现在想知道的是,仅使用基本的“read.csv()”就可以加载整个数据吗?应该没问题吧?因为 fread() 已经成功加载了。
  • 您也可以在read.csv() 周围编写代码以分块读取文件(使用nrowsskip 参数)。 read.csv 也接受 colClasses 参数,这可以帮助您减少内存使用量。我想鉴于fread() 有效,您只是想调试为什么read.csv 阻塞。试试read.csv(..., nrows=1000),然后看看哪些列在消耗你的内存使用量。但老实说,众所周知,基本的read.csv() 在大文件上性能很差,所以我不会花太多时间在上面,这就是用户编写更好的data.table::fread()readr 包的全部原因。
  • @HengchengZhu:我看不出调查read.csv 的性能为何如此糟糕(运行时和内存)的意义。我给你的几乎所有提示也适用于read.csv。如果你愿意,你可以深入研究并发布你的发现。众所周知,read.csv 的性能很差,因此人们编写了更好的实现 data.table::fread()readr 包等。
猜你喜欢
  • 2012-03-10
  • 2020-08-05
  • 2015-06-02
  • 1970-01-01
  • 2019-03-25
  • 2021-05-29
  • 2020-06-22
相关资源
最近更新 更多