![](/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.