6

我在具有 16 GB RAM 的 Linux Mint v12 上运行 Matlab R2011b 和 R 版本 2.13.1。

我有一个 csv 文件。前 5 行(和标题)是:

#RIC,Date[G],Time[G],GMT Offset,Type,Price,Volume
DAEG.OQ,07-JUL-2011,15:10:03.424,-4,Trade,1.68,1008
DAEG.OQ,07-JUL-2011,15:10:03.424,-4,Trade,1.68,1008
DAEG.OQ,07-JUL-2011,15:10:03.424,-4,Trade,1.66,300
DAEG.OQ,07-JUL-2011,15:10:03.424,-4,Trade,1.65,1000
DAEG.OQ,07-JUL-2011,15:10:03.464,-4,Trade,1.65,3180

该文件很大(大约 900MB)。给定字符和数字数据的组合,可以将这个文件读入 matlab,如下所示:

fid1 = fopen('/home/MyUserName/Temp/X.csv');
D = textscan(fid1, '%s%s%s%f%s%f%f', 'Delimiter', ',', 'HeaderLines', 1);
fclose(fid1);

虽然文件是 900MB,但在运行上述代码时,系统监视器显示我的 RAM 使用量从大约 2GB 跃升至 10GB。更糟糕的是,如果我使用稍大的 csv 文件(约 1.2 GB)尝试相同的过程,我的 RAM 最大为 16 GB,而 Matlab 永远无法完成数据的读取(它只是停留在“忙碌”模式)。

如果我想将同一个文件读入 R,我可能会使用:

D <- read.csv("/home/MyUserName/Temp/X.csv", stringsAsFactors=FALSE)

这比 Matlab 需要更长的时间,但系统监视器显示我的 RAM 使用量仅从 2GB 跳到 3.3GB(考虑到原始文件大小更合理)。

我的问题有两个部分:

1)为什么textscan在这种情况下会占用大量内存?

2)我可以使用另一种方法将这种类型的 1.2GB csv 文件放入我系统上的 Matlab 中,而不会耗尽 RAM?

编辑:澄清一下,我很好奇是否存在仅 matlab 的解决方案,即我对涉及使用不同语言将 csv 文件分解成更小的块的解决方案不感兴趣(因为这就是我已经在做)。抱歉 Trav1s,我应该从一开始就说清楚。

4

2 回答 2

2

问题可能是那些“%s”字符串被读入 Matlab cellstrs,这是低基数字符串的内存效率低下的数据结构。对于像这样的大表格数据,Cellstrs 很糟糕。每个字符串最终都存储在一个单独的原始char数组中,每个数组都有大约 400 字节的开销和碎片问题。对于 900MB 的文件,这看起来像 1800 万行;每行 4 个字符串,大约需要 10-20 GB 的 cellstrs 来保存这些字符串。啊。

您想要的是在这些字符串进入时将它们转换为紧凑的原始数据类型,而不是一次将所有 1800 万行全部放入庞大的单元格字符串中。日期和时间戳作为 datenums 或您正在使用的任何数字表示形式,以及那些低基数字符串作为二维char数组或一些等价的分类变量。(鉴于您的数据集大小,您可能希望将这些字符串表示为带有查找表的简单数字标识符,而不是字符。)

一旦你决定了你的紧凑数据结构,有几种方法可以加载它。你可以在纯 Matlab 中将读取分解为块:使用textscan()循环中的调用一次读取 1000 行,解析和转换该块中的 cellstrs 以它们的紧凑形式,缓冲所有结果,并cat在读取结束时将它们放在一起。这将使峰值内存需求降低。

如果您要做很​​多这样的工作,并且性能很重要,您可能希望使用 Java 并编写自己的解析器,该解析器可以在输入字符串和日期时对其进行转换,然后再将它们返回给 Matlab更紧凑的数据类型。这并不难,而且可以从 Matlab 中直接调用 Java 方法,所以这可能只算使用单独的语言。

于 2012-09-26T07:56:18.150 回答
0

对于 2) 你可以尝试使用 csvread 命令。我不知道性能比较如何,但至少它是一种替代方案。

另一种选择是使用更快的语言(如 C 或 awk)读取文件,然后将其分解为更小的文件。顺序读取许多小文件将比一个大文件占用更少的内存。

于 2012-09-19T07:10:09.463 回答