19

我在没有足够 RAM 读取它的计算机上有一个中等大小的文件(4GB CSV)(在 64 位 Windows 上为 8GB)。过去我只是将它加载到集群节点上并读入,但我的新集群似乎任意将进程限制为 4GB 的 RAM(尽管硬件每台机器有 16GB),所以我需要一个短期修复.

有没有办法将 CSV 文件的一部分读入 R 以适应可用的内存限制?这样我可以一次读取文件的三分之一,将其子集到我需要的行和列,然后读取下一个三分之一?

感谢评论者指出我可以使用一些大内存技巧读取整个文件: 快速读取非常大的表格作为 R 中的数据帧

我可以想到一些其他解决方法(例如,在一个好的文本编辑器中打开,删除 2/3 的观察结果,然后在 R 中加载),但如果可能的话,我宁愿避免它们。

因此,现在分段阅读似乎仍然是最好的方法。

4

2 回答 2

32

在查看了这个线程后,我注意到没有提到这个问题的显着解决方案。使用连接!

1)打开到您的文件的连接

con = file("file.csv", "r")

2) 使用 read.csv 读入代码块

read.csv(con, nrows="CHUNK SIZE",...)

旁注:定义 colClasses 将大大加快速度。确保将不需要的列定义为 NULL。

3)做你需要做的事

4) 重复。

5) 关闭连接

close(con)

这种方法的优点是连接。如果您省略这一步,它可能会减慢速度。通过手动打开连接,您实际上打开了数据集并且在调用 close 函数之前不要关闭它。这意味着当您遍历数据集时,您将永远不会失去您的位置。假设您有一个包含 1e7 行的数据集。还假设您想一次加载一大块 1e5 行。由于我们打开连接,我们通过运行获得前 1e5 行read.csv(con, nrow=1e5,...),然后为了获得第二个块,我们也运行read.csv(con, nrow=1e5,...),依此类推....

如果我们不使用连接,我们将以相同的方式获得第一个块read.csv("file.csv", nrow=1e5,...),但是对于下一个块,我们需要read.csv("file.csv", skip = 1e5, nrow=2e5,...)。显然这是低效的。我们必须重新找到 1e5+1 行,尽管我们只是在 1e5 行中读取。

最后,data.table::fread很棒。但是你不能通过它连接。所以这种方法行不通。

我希望这可以帮助别人。

更新

人们一直在支持这篇文章,所以我想我会再补充一个简短的想法。new readr::read_csv, like read.csv,可以传递连接。然而,它被宣传为大约快 10 倍。

于 2015-05-22T18:49:18.937 回答
11

例如,您可以使用 RSQLite 将其读入数据库,然后使用 sql 语句获取一部分。

如果您只需要一个部分,那么read.csv.sql在 sqldf 包中会将数据读入 sqlite 数据库。首先,它为您创建数据库,并且数据不会通过 R,因此 R 的限制将不适用(在这种情况下主要是 RAM)。其次,将数据加载到数据库后,sqldf将指定的sql语句的输出读入R,最后销毁数据库。根据它处理您的数据的速度,如果您有多个部分,您可能只需为每个部分重复整个过程。

只需一行代码即可完成所有三个步骤,因此只需尝试一下即可。

DF <- read.csv.sql("myfile.csv", sql=..., ...other args...)

参见?read.csv.sql以及?sqldf sqldf主页

于 2012-02-19T20:59:22.897 回答