R读取一个巨大的csv

Posted

技术标签:

【中文标题】R读取一个巨大的csv【英文标题】:R reading a huge csv 【发布时间】:2016-11-26 22:26:00 【问题描述】:

我有一个巨大的 csv 文件。它的大小约为 9 GB。我有 16 GB 的内存。我遵循了page 的建议并在下面实施了它们。

If you get the error that R cannot allocate a vector of length x, close out of R and add the following line to the ``Target'' field: 
--max-vsize=500M 

我仍然收到以下错误和警告。我应该如何将 9 GB 的文件读入我的 R?我有 R 64 位 3.3.1,并且我在 rstudio 0.99.903 中运行以下命令。我有 windows server 2012 r2 标准,64 位操作系统。

> memory.limit()
[1] 16383
> answer=read.csv("C:/Users/a-vs/results_20160291.csv")
Error: cannot allocate vector of size 500.0 Mb
In addition: There were 12 warnings (use warnings() to see them)
> warnings()
Warning messages:
1: In scan(file = file, what = what, sep = sep, quote = quote,  ... :
  Reached total allocation of 16383Mb: see help(memory.size)
2: In scan(file = file, what = what, sep = sep, quote = quote,  ... :
  Reached total allocation of 16383Mb: see help(memory.size)
3: In scan(file = file, what = what, sep = sep, quote = quote,  ... :
  Reached total allocation of 16383Mb: see help(memory.size)
4: In scan(file = file, what = what, sep = sep, quote = quote,  ... :
  Reached total allocation of 16383Mb: see help(memory.size)
5: In scan(file = file, what = what, sep = sep, quote = quote,  ... :
  Reached total allocation of 16383Mb: see help(memory.size)
6: In scan(file = file, what = what, sep = sep, quote = quote,  ... :
  Reached total allocation of 16383Mb: see help(memory.size)
7: In scan(file = file, what = what, sep = sep, quote = quote,  ... :
  Reached total allocation of 16383Mb: see help(memory.size)
8: In scan(file = file, what = what, sep = sep, quote = quote,  ... :
  Reached total allocation of 16383Mb: see help(memory.size)
9: In scan(file = file, what = what, sep = sep, quote = quote,  ... :
  Reached total allocation of 16383Mb: see help(memory.size)
10: In scan(file = file, what = what, sep = sep, quote = quote,  ... :
  Reached total allocation of 16383Mb: see help(memory.size)
11: In scan(file = file, what = what, sep = sep, quote = quote,  ... :
  Reached total allocation of 16383Mb: see help(memory.size)
12: In scan(file = file, what = what, sep = sep, quote = quote,  ... :
  Reached total allocation of 16383Mb: see help(memory.size)

------- 更新1

我的第一次尝试基于建议的答案

> thefile=fread("C:/Users/a-vs/results_20160291.csv", header = T)
Read 44099243 rows and 36 (of 36) columns from 9.399 GB file in 00:13:34
Warning messages:
1: In fread("C:/Users/a-vsingh/results_tendo_20160201_20160215.csv",  :
  Reached total allocation of 16383Mb: see help(memory.size)
2: In fread("C:/Users/a-vsingh/results_tendo_20160201_20160215.csv",  :
  Reached total allocation of 16383Mb: see help(memory.size)

------- 更新2

根据建议的答案,我的第二次尝试如下

thefile2 <- read.csv.ffdf(file="C:/Users/a-vs/results_20160291.csv", header=TRUE, VERBOSE=TRUE, 
+                    first.rows=-1, next.rows=50000, colClasses=NA)
read.table.ffdf 1..
Error: cannot allocate vector of size 125.0 Mb
In addition: There were 14 warnings (use warnings() to see them)

如何将这个文件读入单个对象,以便一次分析整个数据

-----------------更新 3

我们买了一台昂贵的机器。它有 10 个内核和 256 GB 内存。这不是最有效的解决方案,但至少在不久的将来会奏效。我看了下面的答案,但我认为它们不能解决我的问题:(我很欣赏这些答案。我想执行市场篮子分析,我认为除了将我的数据保存在 RAM 中之外别无他法

【问题讨论】:

Trimming a huge (3.5 GB) csv file to read into R的可能重复 你能指定你打算如何处理数据吗?特别是如果您的第一步是汇总它们或仅使用一些变量? ff 是一个解决方案,但相关性取决于您将做什么。另一种选择是例如结合 ff 读取然后存储在数据库中 - 您可能对 MonetDB 中的这方面感兴趣,并入 MonetDBLite 请告诉我们文件中的行数和列数。 @EricLecoutre 我计划探索数据。一旦我绘制并更好地理解它,我可能会删除一些行和/或列 @user1436187 36 列和 47,368,186 行... 【参考方案1】:

确保您使用的是 64 位 R,而不仅仅是 64 位 Windows,以便您可以将 RAM 分配增加到全部 16 GB。

另外,可以分块读入文件:

file_in    <- file("in.csv","r")
chunk_size <- 100000 # choose the best size for you
x          <- readLines(file_in, n=chunk_size)

您可以使用data.table 更有效地处理读取和操作大文件:

require(data.table)
fread("in.csv", header = T)

如果需要,您可以通过 ff 来利用存储内存:

library("ff")
x <- read.csv.ffdf(file="file.csv", header=TRUE, VERBOSE=TRUE, 
                   first.rows=10000, next.rows=50000, colClasses=NA)

【讨论】:

我试过thefile=fread("C:/Users/a-vs/results_20160291.csv", header = T) 并收到一条消息Warning messages: 1: In fread("C:/Users/a-vs/results_20160291.csv", : Reached total allocation of 16383Mb: see help(memory.size) 我怎样才能将这个文件读入单个对象,以便我可以一次分析整个数据 @user2543622 使用ff。但只是为了记录,将大文件分块是大数据中的标准做法。另一个答案是您可以先在 SQL 中对数据进行一些预处理。也许一旦你在 R 中得到它,你也可以将其中的一些发送到一个稀疏矩阵。【参考方案2】:

这在您的计算机上可能无法实现。在某些情况下,data.table.csv 占用更多空间。

DT <- data.table(x = sample(1:2,10000000,replace = T))
write.csv(DT, "test.csv") #29 MB file
DT <- fread("test.csv", row.names = F)   
object.size(DT)
> 40001072 bytes #40 MB

两个OOM大:

DT <- data.table(x = sample(1:2,1000000000,replace = T))
write.csv(DT, "test.csv") #2.92 GB file
DT <- fread("test.csv", row.names = F)   
object.size(DT)
> 4000001072 bytes #4.00 GB

在 R 中存储对象存在自然开销。根据这些数字,读取文件时大约有 1.33 倍,但是,这取决于数据。例如,使用

x = sample(1:10000000,10000000,replace = T) 给出的因子大约是 2 倍 (R:csv)。

x = sample(c("foofoofoo","barbarbar"),10000000,replace = T) 给出 0.5 倍 (R:csv) 的系数。

根据最大值,您的 9GB 文件可能需要 18GB 的​​内存来存储在 R 中,如果不是更多的话。根据您的错误消息,您更有可能遇到硬内存限制而不是分配问题。因此,仅在夹头中读取文件并进行合并是行不通的-您还需要对分析+工作流程进行分区。另一种选择是使用 SQL 等内存工具。

【讨论】:

【参考方案3】:

这将是一种可怕的做法,但根据您需要如何处理这些数据,它不应该糟糕。您可以通过调用memory.limit(new) 来更改R 允许使用的最大内存,其中new 是一个整数,其中R 的新memory.limitMB 中。将会发生的情况是,当您遇到硬件限制时,Windows 将开始将内存分页到硬盘驱动器上(这不是世界上最糟糕的事情,但它会严重减慢您的处理速度)。

如果您在服务器版本上运行它,则 Windows 分页可能(很可能)与常规 Windows 10 不同。我相信它应该更快,因为服务器操作系统应该针对这些东西进行优化。

尝试从 32 GB(或 memory.limit(memory.limit()*2))开始,如果结果比这大得多,我会说程序最终会变得太慢它被加载到内存中。那时我会建议购买更多的 RAM 或找到一种方法来部分处理。

【讨论】:

【参考方案4】:

您可能想要考虑利用一些磁盘上的处理,而不是将整个对象都放在 R 的内存中。一种选择是将数据存储在适当的数据库中,然后让 R 访问该数据库。 dplyr 能够处理远程源(它实际上是编写 SQL 语句来查询数据库)。我刚刚用一个小例子(只有 17,500 行)对此进行了测试,但希望它可以扩展到您的要求。

安装 SQLite

https://www.sqlite.org/download.html

将数据输入新的 SQLite 数据库

将以下内容保存在名为import.sql 的新文件中

CREATE TABLE tableName (COL1, COL2, COL3, COL4); .separator , .import YOURDATA.csv tableName

是的,您需要自己指定列名(我相信),但如果您愿意,也可以在此处指定它们的类型。当然,如果您的姓名/数据中有逗号,这将不起作用。

通过命令行将数据导入SQLite数据库

sqlite3.exe BIGDATA.sqlite3 < import.sql

dplyr 指向 SQLite 数据库

当我们使用 SQLite 时,所有依赖项都已由 dplyr 处理。

library(dplyr) my_db <- src_sqlite("/PATH/TO/YOUR/DB/BIGDATA.sqlite3", create = FALSE) my_tbl <- tbl(my_db, "tableName")

进行探索性分析

dplyr 将编写查询此数据源所需的 SQLite 命令。否则它将表现得像一个本地表。最大的例外是您无法查询行数。

my_tbl %>% group_by(COL2) %>% summarise(meanVal = mean(COL3))

#>  Source:   query [?? x 2]
#>  Database: sqlite 3.8.6 [/PATH/TO/YOUR/DB/BIGDATA.sqlite3]
#>  
#>         COL2    meanVal
#>        <chr>      <dbl>
#>  1      1979   15.26476
#>  2      1980   16.09677
#>  3      1981   15.83936
#>  4      1982   14.47380
#>  5      1983   15.36479

【讨论】:

这是一个很好的建议!太感谢了!我一直在处理一个非常大的 csv 文件。我现在将按照您的建议尝试 sqlite。谢谢!【参考方案5】:

您可以尝试在表格中拆分处理。不要对整个事情进行操作,而是将整个操作放在for 循环中,然后执行 16、32、64 次,或者您需要执行多少次。可以保存以后计算所需的任何值。这没有其他帖子那么快,但它肯定会返回。

x = number_of_rows_in_file / CHUNK_SIZE
for (i in c(from = 1, to = x, by = 1)) 
    read.csv(con, nrows=CHUNK_SIZE,...)

希望对您有所帮助。

【讨论】:

以上是关于R读取一个巨大的csv的主要内容,如果未能解决你的问题,请参考以下文章

如何按行条件将巨大的 csv 文件读入 R?

有效地读取巨大的 csv 文件?

用 matlab 读取巨大的 .csv 文件 - 文件组织得不好

读取R中的CSV作为数据帧

使用标题中带有数字符号的变量读取 csv 问题 [r]

读取缺少逗号的 .csv 文件。碱基R