当前位置:  开发笔记 > 编程语言 > 正文

修剪一个巨大的(3.5 GB)csv文件以读入R

如何解决《修剪一个巨大的(3.5GB)csv文件以读入R》经验,为你挑选了7个好方法。

所以我有一个数据文件(分号分隔),它有很多细节和不完整的行(导致Access和SQL扼流).它的县级数据集分为段,子段和子子段(总共约200个因子),为期40年.简而言之,它是巨大的,如果我试着简单地阅读它,它就不适应内存.

所以我的问题是,鉴于我想要所有的县,但只有一年(而且只是最高级别的细分......最终导致大约100,000行),最好的方法是什么汇总到R?

目前我正试图用Python来消除不相关的年份,通过一次读取和操作一行来绕过文件大小限制,但我更喜欢只有R的解决方案(CRAN包可以).有没有类似的方法在R中一次读取一个文件?

任何想法将不胜感激.

更新:

约束

需要使用我的机器,所以没有EC2实例

仅作为R-only.在这种情况下速度和资源不是问题...只要我的机器不爆炸...

如下所示,数据包含混合类型,我需要稍后进行操作

数据

数据为3.5GB,大约850万行和17列

几千行(~2k)格式错误,只有一列而不是17列

这些完全不重要,可以放弃

我只需要这个文件中的~10,000行(见下文)

数据示例:

County; State; Year; Quarter; Segment; Sub-Segment; Sub-Sub-Segment; GDP; ...
Ada County;NC;2009;4;FIRE;Financial;Banks;80.1; ...
Ada County;NC;2010;1;FIRE;Financial;Banks;82.5; ...
NC  [Malformed row]
[8.5 Mill rows]

我想砍掉一些列并从40个可用年份中挑选两个(2009-2010从1980年到2020年),这样数据可以适用于R:

County; State; Year; Quarter; Segment; GDP; ...
Ada County;NC;2009;4;FIRE;80.1; ...
Ada County;NC;2010;1;FIRE;82.5; ...
[~200,000 rows]

结果:

在修改了所有建议后,我认为JD和Marek建议的readLines效果最好.我给了Marek支票,因为他提供了一个示例实施.

我在这里为我的最终答案复制了一个略微改编的Marek实现版本,使用strsplit和cat来保留我想要的列.

还应当指出,这是MUCH比Python效率较低......在,巨蟒通过要吃掉5分钟3.5GB文件,而R取约60 ...但如果你只为R,那么这是罚单.

## Open a connection separately to hold the cursor position
file.in <- file('bad_data.txt', 'rt')
file.out <- file('chopped_data.txt', 'wt')
line <- readLines(file.in, n=1)
line.split <- strsplit(line, ';')
# Stitching together only the columns we want
cat(line.split[[1]][1:5], line.split[[1]][8], sep = ';', file = file.out, fill = TRUE)
## Use a loop to read in the rest of the lines
line <- readLines(file.in, n=1)
while (length(line)) {
  line.split <- strsplit(line, ';')
  if (length(line.split[[1]]) > 1) {
    if (line.split[[1]][3] == '2009') {
        cat(line.split[[1]][1:5], line.split[[1]][8], sep = ';', file = file.out, fill = TRUE)
    }
  }
  line<- readLines(file.in, n=1)
}
close(file.in)
close(file.out)

方法失败:

sqldf

如果数据格式正确,这绝对是我将来用于此类问题的方法.但是,如果不是,则SQLite会窒息.

MapReduce的

说实话,文档在这个问题上对我进行了恐吓,所以我没有尝试过.它看起来像是需要对象在内存中,如果是这样的话,这将打败这一点.

bigmemory

这种方法与数据干净地链接,但它一次只能处理一种类型.结果,当放入big.table时,我的所有角色向量都会丢失.如果我需要为未来设计大型数据集,我会考虑仅使用数字来保持此选项的活跃性.

扫描

扫描似乎与大内存有类似的类型问题,但具有readLines的所有机制.简而言之,这次只是不适合这个法案.

Marek.. 38

我的尝试readLines.这段代码创建csv了选定的年份.

file_in <- file("in.csv","r")
file_out <- file("out.csv","a")
x <- readLines(file_in, n=1)
writeLines(x, file_out) # copy headers

B <- 300000 # depends how large is one pack
while(length(x)) {
    ind <- grep("^[^;]*;[^;]*; 20(09|10)", x)
    if (length(ind)) writeLines(x[ind], file_out)
    x <- readLines(file_in, n=B)
}
close(file_in)
close(file_out)


Shane.. 10

我不是这方面的专家,但你可能会考虑尝试MapReduce,这基本上意味着采取"分而治之"的方法.R有几种选择,包括:

    mapReduce(纯R)

    RHIPE(使用Hadoop); 有关子集化文件示例,请参阅文档中的示例6.2.2

或者,R提供了几个软件包来处理外部存储器(磁盘上)的大数据.您可以将整个数据集加载到一个bigmemory对象中并在R中完全进行缩减.请参阅http://www.bigmemory.org/以获取一组处理此问题的工具.



1> Marek..:

我的尝试readLines.这段代码创建csv了选定的年份.

file_in <- file("in.csv","r")
file_out <- file("out.csv","a")
x <- readLines(file_in, n=1)
writeLines(x, file_out) # copy headers

B <- 300000 # depends how large is one pack
while(length(x)) {
    ind <- grep("^[^;]*;[^;]*; 20(09|10)", x)
    if (length(ind)) writeLines(x[ind], file_out)
    x <- readLines(file_in, n=B)
}
close(file_in)
close(file_out)



2> Shane..:

我不是这方面的专家,但你可能会考虑尝试MapReduce,这基本上意味着采取"分而治之"的方法.R有几种选择,包括:

    mapReduce(纯R)

    RHIPE(使用Hadoop); 有关子集化文件示例,请参阅文档中的示例6.2.2

或者,R提供了几个软件包来处理外部存储器(磁盘上)的大数据.您可以将整个数据集加载到一个bigmemory对象中并在R中完全进行缩减.请参阅http://www.bigmemory.org/以获取一组处理此问题的工具.



3> JD Long..:

有没有类似的方法在R中一次读取一个文件?

是.readChar()函数将在字符的块读取,而不假定它们是空终止.如果要一次读取一行中的数据,可以使用readLines().如果你读取一个块或一行,做一个操作,然后写出数据,就可以避免内存问题.虽然如果你想在亚马逊的EC2上启动一个大内存实例,你可以获得高达64GB的内存.这应该保存你的文件加上足够的空间来操纵数据.

如果你需要更快的速度,那么Shane建议使用Map Reduce是一个非常好的建议.但是,如果您在EC2上使用大内存实例的路线,您应该查看多核软件包以使用计算机上的所有内核.

如果您发现自己想要将许多分隔数据读入R中,您至少应该研究sqldf包,它允许您从R直接导入sqldf,然后对R内的数据进行操作.我发现sqldf是一个如上一个问题所述,将数据输入R的最快方法.



4> Ali..:

ff包是一种处理大文件的透明方式.

您可能会看到包裹网站和/或有关它的演示文稿.

我希望这有帮助



5> Marek..:

您可以将数据导入SQLite数据库,然后使用RSQLite选择子集.



6> Ari B. Fried..:

有一个名为colbycol的全新软件包,它允许您只从大量文本文件中读取所需的变量:

http://colbycol.r-forge.r-project.org/

它将任何参数传递给read.table,因此组合应该让您非常紧密地进行子集化.



7> Rentrop..:

使用readrread_*_chunked家人怎么样?

所以在你的情况下:

testfile.csv

County; State; Year; Quarter; Segment; Sub-Segment; Sub-Sub-Segment; GDP
Ada County;NC;2009;4;FIRE;Financial;Banks;80.1
Ada County;NC;2010;1;FIRE;Financial;Banks;82.5
lol
Ada County;NC;2013;1;FIRE;Financial;Banks;82.5

实际代码

require(readr)
f <- function(x, pos) subset(x, Year %in% c(2009, 2010))
read_csv2_chunked("testfile.csv", DataFrameCallback$new(f), chunk_size = 1)

这适用f于每个块,记住col-names并最终组合过滤后的结果.看看?callback这个例子的来源.

这导致:

# A tibble: 2 × 8
      County State  Year Quarter Segment `Sub-Segment` `Sub-Sub-Segment`   GDP
*                                     
1 Ada County    NC  2009       4    FIRE     Financial             Banks   801
2 Ada County    NC  2010       1    FIRE     Financial             Banks   825

你甚至可以增加,chunk_size但在这个例子中只有4行.

推荐阅读
低调pasta_730
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有