CSV文件单列读取的更快方式

15
我希望尽快地将CSV文件的单个列读入R中。我希望通过一种比标准方法更快的方式将该列读入RAM,以缩短所需时间的十倍。我的动机是什么呢?我有两个文件,一个名为Main.csv,有300000行和500列,另一个名为Second.csv,有300000行和5列。如果我使用system.time()命令 read.csv("Second.csv"),需要2.2秒。现在,如果我使用以下任何一种方法之一来读取Main.csv的第一列(因为它只有1列而不是5列,所以是Second.csv大小的20%),那么将需要超过40秒。这与读取整个600兆字节文件的时间相同,显然无法接受。
  • 方法1
  • colClasses <- rep('NULL',500)
    
    colClasses[1] <- NA
    system.time(
    read.csv("Main.csv",colClasses=colClasses)
    ) # 40+ seconds, unacceptable
    
  • 方法二

  •  read.table(pipe("cut -f1 Main.csv")) #40+ seconds, unacceptable
    

如何缩短这个时间?我希望有一个 R 解决方案。


@zero323 我需要一个可以在Python、Java和R中进行io的东西。 - user2763361
我的旧POC包可能会在这里很有趣,它提供了一种以特殊的二进制格式编写data.frame的方法,可以稍后仅读取少量变量。基本上,它是save/readRDS的包装器,并将列写入单独的文件等。更多细节请参见:https://dev59.com/Dm445IYBdhLWcg3wpb8P - daroczig
@SimonO101 你能举个例子如何读取单列吗?我使用了与我的示例相同的 colClasses,但它只会读取整个 600Mb 的数据表(所有 500 列)? - user2763361
3
您的CSV文件是否真的以逗号分隔?我认为尝试一下scan(pipe("cut -f1 -d, Main.csv"))可能会有帮助。 - Ben Bolker
@SimonO101 我稍后会测试一下。感谢您一直以来的贡献。 - user2763361
显示剩余7条评论
2个回答

14
我建议。
scan(pipe("cut -f1 -d, Main.csv"))

这与原始提案 (read.table(pipe("cut -f1 Main.csv"))) 有几个不同之处:

  • 因为文件是逗号分隔的,而 cut 默认情况下假定制表符分隔,所以您需要指定 d, 来指定逗号分隔。
  • scan()read.table 在读取简单/非结构化数据时更快。

根据 OP 的评论,这大约需要 4 秒而不是 40 多秒。


在读取文件之前,使用Linux命令行嵌套真是太神奇了。我甚至可以将我的Python清洗器放在管道命令中,在读取原始文件之前清理数据!我想知道是否有可能使用scan有效地逐行(每行一个)从stdin读取表格? - B.Mr.W.
绝对精彩。 - user2763361
@B.Mr.W.:恐怕你不会有太大的进展(我在其他地方看到了你的问题,但是你的限制非常严格:很难想出一种在R中逐行读取的方法而没有太多的开销)。我认为scan不会比readLines更快,但你为什么不试试看它的效果如何呢? - Ben Bolker
@BenBolker 实际上你可以直接使用系统命令来使用 fread,所以这个... fread( "cut -f1 -d, Main.csv" ) 可能会 更快? - Simon O'Hanlon
也许吧,但是与read.table()相比,scan()的开销确实不大。 - Ben Bolker

11

这个博客展示了读取大型CSV文件的方法速度比较。其中,fread 是最快的。

如上面评论中提到的,您可以使用 select 参数来选择要读取的列 - 因此:

fread("main.csv",sep = ",", select = c("f1") ) 

会运作


您是否可以选择读取哪些行?例如,按列条件选择行?即SELECT col_1, col_2 FROM file WHERE col_3 > 30fread等效函数。 - Anarcho-Chossid

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