![](/img/trans.png)
[英]R: Memory Management during xmlEventParse of Huge (>20GB) files
[英]Read a 20GB file in chunks without exceeding my RAM - R
我目前正在尝试读取 20GB 的文件。 我只需要该文件的 3 列。 我的问题是,我只能使用 16 GB 的内存。 我尝试使用readr
并使用函数read_csv_chunked
和read_csv
和 skip 参数以块的形式处理数据,但这些都超出了我的 RAM 限制。 甚至读取一行的read_csv(file, ..., skip = 10000000, nrow = 1)
调用也read_csv(file, ..., skip = 10000000, nrow = 1)
了我所有的 RAM。
我现在的问题是,我怎样才能读取这个文件? 有没有办法在不使用那么多内存的情况下读取文件块?
LaF包可以以块的形式读取 ASCII 数据。 它可以直接使用,或者如果您使用dplyr,则分块包使用它提供与 dplyr 一起使用的接口。
readr包有readr_csv_chunked和相关函数。
本网页中名为The Loop 的部分以及该页面的后续部分描述了如何使用基础 R 进行分块读取。
可能是,如果您删除除前三列之外的所有列,它会小到足以一次性读取并处理它。
vroom
包中的vroom可以非常快速地读入文件,并且还能够仅读入select=
参数中命名的列,这可能使它足够小,可以一口气读入。
data.table包中的fread
是一个快速读取函数,它也支持select=
参数,它只能选择指定的列。
read.csv.sql
(另见github页面)包中的read.csv.sql可以读取一个大于R可以处理的文件到一个临时的外部SQLite数据库中,它为你创建并随后删除并读取给R的SQL语句的结果。如果前三列被命名为 col1、col2 和 col3,请尝试下面的代码。 有关取决于您的文件的其余参数,请参阅 ?read.csv.sql 和 ?sqldf 。
library(sqldf)
DF <- read.csv.sql("myfile", "select col1, col2, col3 from file",
dbname = tempfile(), ...)
R 基础中的read.table
和read.csv
有一个colClasses=
参数,它采用列类向量。 如果文件有 nc 列,则使用colClasses = rep(c(NA, "NULL"), c(3, nc-3))
仅读取前 3 列。
另一种方法是使用 cut、sed 或 awk(在 UNIX 和 Windows 上的 Rtools bin 目录中本机可用)或许多免费命令行实用程序(例如 R 之外的csvfix )中的任何一个来预处理文件,以删除除前三列,然后看看它是否足够小,可以一口气读完。
另请查看高性能计算任务视图。
我们可以尝试这样的事情,首先是一个小例子 csv:
X = data.frame(id=1:1e5,matrix(runi(1e6),ncol=10))
write.csv(X,"test.csv",quote=F,row.names=FALSE)
您可以使用 nrow 函数,而不是提供文件,而是提供连接,并将结果存储在列表中,例如:
data = vector("list",200)
con = file("test.csv","r")
data[[1]] = read.csv(con, nrows=1000)
dim(data[[1]])
COLS = colnames(data[[1]])
data[[1]] = data[[1]][,1:3]
head(data[[1]])
id X1 X2 X3
1 1 0.13870273 0.4480100 0.41655108
2 2 0.82249489 0.1227274 0.27173937
3 3 0.78684815 0.9125520 0.08783347
4 4 0.23481987 0.7643155 0.59345660
5 5 0.55759721 0.6009626 0.08112619
6 6 0.04274501 0.7234665 0.60290296
在上面,我们读取了第一个块,收集了列名并进行了子集化。 如果您继续阅读连接,标题将丢失,我们需要指定:
for(i in 2:200){
data[[i]] = read.csv(con, nrows=1000,col.names=COLS,header=FALSE)[,1:3]
}
最后,我们将所有这些构建到一个 data.frame 中:
data = do.call(rbind,data)
all.equal(data[,1:3],X[,1:3])
[1] TRUE
你可以看到我指定了一个比需要的大得多的列表,这是为了显示如果你不知道文件有多长,当你指定更大的东西时,它应该可以工作。 这比写一个while循环要好一些..
所以我们把它包装成一个函数,指定文件,一次读取的行数,次数,以及要子集的列名(或位置):
read_chunkcsv=function(file,rows_to_read,ntimes,col_subset){
data = vector("list",rows_to_read)
con = file(file,"r")
data[[1]] = read.csv(con, nrows=rows_to_read)
COLS = colnames(data[[1]])
data[[1]] = data[[1]][,col_subset]
for(i in 2:ntimes){
data[[i]] = read.csv(con,
nrows=rows_to_read,col.names=COLS,header=FALSE)[,col_subset]
}
return(do.call(rbind,data))
}
all.equal(X[,1:3],
read_chunkcsv("test.csv",rows_to_read=10000,ntimes=10,1:3))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.