繁体   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