读取一个大型CSV文件

37

我有一个巨大的csv文件,大小约为9GB。我的内存是16GB。我按照这个页面上的建议实施了以下操作。

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个核心和256GB内存。虽然不是最有效的解决方案,但至少在不久的将来它能够工作。我查看了以下答案,我不认为它们能解决我的问题:(感谢这些答案)我想要执行市场篮子分析,我认为除了将数据保存在RAM中没有其他办法。

2
可能是将一个巨大的(3.5 GB)CSV文件剪裁以便读入R的重复问题。 - HFBrowning
1
你能具体说明一下你打算如何处理这些数据吗?特别是如果你的第一步是聚合它们或仅使用其中的某些变量。ff 是一个解决方案,但其相关性取决于你将要做什么。另一个选项是将 ff 与读取后存储在数据库中进行组合--你可能会对 MonetDBLite 包中包含的 MonetDB 感兴趣。 - Eric Lecoutre
请告诉我们您的文件中有多少行和列。 - user1436187
@EricLecoutre 我打算探索这些数据。一旦我绘制出来并更好地理解它,我可能会删除一些行和/或列。 - user2543622
@user1436187 36列和47,368,186行... - user2543622
相关文章:https://dev59.com/OWw05IYBdhLWcg3wSABH - Tung
5个回答

32

确保你使用的是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
3
@user2543622 使用ff。但是要记录的是将大文件分块成小块在大数据中是一种常见做法。另一个答案是您可以首先在 SQL 中对数据进行一些预处理。也许一旦您将其转换到 R 中,还可以将其中的一部分发送到稀疏矩阵中。 - Hack-R

18

您可能需要考虑利用一些磁盘处理方式,而不是将整个对象存储在 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。谢谢! - Michel Mesquita

12

在某些情况下,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。


2

这样做并不是最好的实践方法,但根据你需要处理这些数据的方式,情况可能不会太糟糕。你可以调用memory.limit(new) 来更改 R 允许使用的最大内存,其中 new 是一个整数,表示 R 的新的memory.limit(以MB为单位)。当硬件限制被触及时,Windows 将开始将内存分页到硬盘上(这不是世界上最糟糕的事情,但会严重减慢你的处理速度)。

如果你在服务器版本的 Windows 上运行本程序,则分页可能会与常规的 Windows 10 不同。我认为它应该更快,因为服务器操作系统应该针对此类问题进行了优化。

尝试从32 GB(或 memory.limit(memory.limit()*2)) 开始,如果超出了这个值很多,那么一旦加载到内存中,该程序将变得过于缓慢。此时我建议购买更多的RAM或找到一种按部就班的处理方法。


2

你可以尝试将处理过程拆分到表格中。不要对整个表格进行操作,而是将整个操作放在一个 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,...)
}

希望这可以帮到您。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接