簡體   English   中英

在不超過我的 RAM 的情況下以塊形式讀取 20GB 文件 - R

[英]Read a 20GB file in chunks without exceeding my RAM - R

我目前正在嘗試讀取 20GB 的文件。 我只需要該文件的 3 列。 我的問題是,我只能使用 16 GB 的內存。 我嘗試使用readr並使用函數read_csv_chunkedread_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.tableread.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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM