所以我有一个数据文件(分号分隔),它有很多细节和不完整的行(导致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/以获取一组处理此问题的工具.
我的尝试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)
我不是这方面的专家,但你可能会考虑尝试MapReduce,这基本上意味着采取"分而治之"的方法.R有几种选择,包括:
mapReduce(纯R)
RHIPE(使用Hadoop); 有关子集化文件示例,请参阅文档中的示例6.2.2
或者,R提供了几个软件包来处理外部存储器(磁盘上)的大数据.您可以将整个数据集加载到一个bigmemory
对象中并在R中完全进行缩减.请参阅http://www.bigmemory.org/以获取一组处理此问题的工具.
有没有类似的方法在R中一次读取一个文件?
是.的readChar()函数将在字符的块读取,而不假定它们是空终止.如果要一次读取一行中的数据,可以使用readLines().如果你读取一个块或一行,做一个操作,然后写出数据,就可以避免内存问题.虽然如果你想在亚马逊的EC2上启动一个大内存实例,你可以获得高达64GB的内存.这应该保存你的文件加上足够的空间来操纵数据.
如果你需要更快的速度,那么Shane建议使用Map Reduce是一个非常好的建议.但是,如果您在EC2上使用大内存实例的路线,您应该查看多核软件包以使用计算机上的所有内核.
如果您发现自己想要将许多分隔数据读入R中,您至少应该研究sqldf包,它允许您从R直接导入sqldf,然后对R内的数据进行操作.我发现sqldf是一个如上一个问题所述,将数据输入R的最快方法.
该ff
包是一种处理大文件的透明方式.
您可能会看到包裹网站和/或有关它的演示文稿.
我希望这有帮助
您可以将数据导入SQLite数据库,然后使用RSQLite选择子集.
有一个名为colbycol的全新软件包,它允许您只从大量文本文件中读取所需的变量:
http://colbycol.r-forge.r-project.org/
它将任何参数传递给read.table,因此组合应该让您非常紧密地进行子集化.
使用readr
和read_*_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行.