所以我有一个数据文件(分号分隔),它有很多细节和不完整的行(导致Access和SQL扼流).它的县级数据集分为段,子段和子子段(总共约200个因子),为期40年.简而言之,它是巨大的,如果我试着简单地阅读它,它就不适应内存.
所以我的问题是,鉴于我想要所有的县,但只有一年(而且只是最高级别的细分......最终导致大约100,000行),最好的方法是什么汇总到R?
目前我正试图用Python来消除不相关的年份,通过一次读取和操作一行来绕过文件大小限制,但我更喜欢只有R的解决方案(CRAN包可以).有没有类似的方法在R中一次读取一个文件?
任何想法将不胜感激.
更新:
数据示例:
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]
Run Code Online (Sandbox Code Playgroud)
我想砍掉一些列并从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]
Run Code Online (Sandbox Code Playgroud)
结果:
在修改了所有建议后,我认为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)
Run Code Online (Sandbox Code Playgroud)
方法失败:
Mar*_*rek 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)
Run Code Online (Sandbox Code Playgroud)
JD *_*ong 10
有没有类似的方法在R中一次读取一个文件?
是.的readChar()函数将在字符的块读取,而不假定它们是空终止.如果要一次读取一行中的数据,可以使用readLines().如果你读取一个块或一行,做一个操作,然后写出数据,就可以避免内存问题.虽然如果你想在亚马逊的EC2上启动一个大内存实例,你可以获得高达64GB的内存.这应该保存你的文件加上足够的空间来操纵数据.
如果你需要更快的速度,那么Shane建议使用Map Reduce是一个非常好的建议.但是,如果您在EC2上使用大内存实例的路线,您应该查看多核软件包以使用计算机上的所有内核.
如果您发现自己想要将许多分隔数据读入R中,您至少应该研究sqldf包,它允许您从R直接导入sqldf,然后对R内的数据进行操作.我发现sqldf是一个如上一个问题所述,将数据输入R的最快方法.
有一个名为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
Run Code Online (Sandbox Code Playgroud)
实际代码
require(readr)
f <- function(x, pos) subset(x, Year %in% c(2009, 2010))
read_csv2_chunked("testfile.csv", DataFrameCallback$new(f), chunk_size = 1)
Run Code Online (Sandbox Code Playgroud)
这适用f于每个块,记住col-names并最终组合过滤后的结果.看看?callback这个例子的来源.
这导致:
# A tibble: 2 × 8
County State Year Quarter Segment `Sub-Segment` `Sub-Sub-Segment` GDP
* <chr> <chr> <int> <int> <chr> <chr> <chr> <dbl>
1 Ada County NC 2009 4 FIRE Financial Banks 801
2 Ada County NC 2010 1 FIRE Financial Banks 825
Run Code Online (Sandbox Code Playgroud)
你甚至可以增加,chunk_size但在这个例子中只有4行.