我有一个非常大的表(3000万行),我想在r中作为数据框架加载,read.table()有很多方便的特性,但似乎在实现中有很多逻辑会减慢速度。在我的例子中,我假设我事先知道列的类型,表不包含任何列标题或行名,也没有任何需要担心的病态字符。

我知道使用scan()将表读入为列表可以相当快,例如:

datalist <- scan('myfile',sep='\t',list(url='',popularity=0,mintime=0,maxtime=0)))

但我试图将其转换为数据框架的一些尝试似乎将上述性能降低了6倍:

df <- as.data.frame(scan('myfile',sep='\t',list(url='',popularity=0,mintime=0,maxtime=0))))

有更好的办法吗?或者完全不同的解决问题的方法?


当前回答

一个小的附加点值得一提。如果你有一个非常大的文件,你可以在运行中计算行数(如果没有头文件)使用(其中bedGraph是你的文件在你的工作目录中的名称):

>numRow=as.integer(system(paste("wc -l", bedGraph, "| sed 's/[^0-9.]*\\([0-9.]*\\).*/\\1/'"), intern=T))

你可以在read。csv, read中使用。表格

>system.time((BG=read.table(bedGraph, nrows=numRow, col.names=c('chr', 'start', 'end', 'score'),colClasses=c('character', rep('integer',3)))))
   user  system elapsed 
 25.877   0.887  26.752 
>object.size(BG)
203949432 bytes

其他回答

这是几年后的一次更新

这个答案是旧的,而R已经继续了。调整阅读。表跑得快一点没有什么好处。你的选择是:

Using vroom from the tidyverse package vroom for importing data from csv/tab-delimited files directly into an R tibble. See Hector's answer. Using fread in data.table for importing data from csv/tab-delimited files directly into R. See mnel's answer. Using read_table in readr (on CRAN from April 2015). This works much like fread above. The readme in the link explains the difference between the two functions (readr currently claims to be "1.5-2x slower" than data.table::fread). read.csv.raw from iotools provides a third option for quickly reading CSV files. Trying to store as much data as you can in databases rather than flat files. (As well as being a better permanent storage medium, data is passed to and from R in a binary format, which is faster.) read.csv.sql in the sqldf package, as described in JD Long's answer, imports data into a temporary SQLite database and then reads it into R. See also: the RODBC package, and the reverse depends section of the DBI package page. MonetDB.R gives you a data type that pretends to be a data frame but is really a MonetDB underneath, increasing performance. Import data with its monetdb.read.csv function. dplyr allows you to work directly with data stored in several types of database. Storing data in binary formats can also be useful for improving performance. Use saveRDS/readRDS (see below), the h5 or rhdf5 packages for HDF5 format, or write_fst/read_fst from the fst package.


原来的答案

无论你是否使用read,都有一些简单的事情可以尝试。表或扫描。

设置nrows=数据中的记录数量(扫描中的nmax)。 确保你的评论。Char =""关闭注释的解释。 使用read.table中的colClasses显式定义每列的类。 设置多。line=FALSE也可以提高扫描的性能。

如果这些都不起作用,那么使用一个概要包来确定哪些行减慢了速度。也许你可以写一个删减版的read。表基于结果。

另一种方法是在将数据读入R之前过滤数据。

或者,如果问题是必须定期读入,那么使用这些方法一次性读入数据,然后使用save saveRDS将数据帧保存为二进制blob,然后下次使用load readRDS可以更快地检索它。

另一种选择是使用vroom包。现在在CRAN。 Vroom不加载整个文件,它索引每条记录所在的位置,并在稍后使用它时读取。

只按使用付费。

请参阅vroom介绍,开始使用vroom和vroom基准。

基本的概述是,对一个大文件的初始读取将会快得多,而对数据的后续修改可能会稍微慢一些。所以根据你的用途,这可能是最好的选择。

查看下面vroom基准测试的简化示例,关键部分是超快的读取时间,但稍微播种操作,如聚合等。

package                 read    print   sample   filter  aggregate   total
read.delim              1m      21.5s   1ms      315ms   764ms       1m 22.6s
readr                   33.1s   90ms    2ms      202ms   825ms       34.2s
data.table              15.7s   13ms    1ms      129ms   394ms       16.3s
vroom (altrep) dplyr    1.7s    89ms    1.7s     1.3s    1.9s        6.7s

下面是一个使用fread from data的例子。表1.8.7

这些例子来自我的windows XP Core 2 duo E8400上的帮助页面。

library(data.table)
# Demo speedup
n=1e6
DT = data.table( a=sample(1:1000,n,replace=TRUE),
                 b=sample(1:1000,n,replace=TRUE),
                 c=rnorm(n),
                 d=sample(c("foo","bar","baz","qux","quux"),n,replace=TRUE),
                 e=rnorm(n),
                 f=sample(1:1000,n,replace=TRUE) )
DT[2,b:=NA_integer_]
DT[4,c:=NA_real_]
DT[3,d:=NA_character_]
DT[5,d:=""]
DT[2,e:=+Inf]
DT[3,e:=-Inf]

标准read.table

write.table(DT,"test.csv",sep=",",row.names=FALSE,quote=FALSE)
cat("File size (MB):",round(file.info("test.csv")$size/1024^2),"\n")    
## File size (MB): 51 

system.time(DF1 <- read.csv("test.csv",stringsAsFactors=FALSE))        
##    user  system elapsed 
##   24.71    0.15   25.42
# second run will be faster
system.time(DF1 <- read.csv("test.csv",stringsAsFactors=FALSE))        
##    user  system elapsed 
##   17.85    0.07   17.98

优化read.table

system.time(DF2 <- read.table("test.csv",header=TRUE,sep=",",quote="",  
                          stringsAsFactors=FALSE,comment.char="",nrows=n,                   
                          colClasses=c("integer","integer","numeric",                        
                                       "character","numeric","integer")))


##    user  system elapsed 
##   10.20    0.03   10.32

从文件中读

require(data.table)
system.time(DT <- fread("test.csv"))                                  
 ##    user  system elapsed 
##    3.12    0.01    3.22

sqldf

require(sqldf)

system.time(SQLDF <- read.csv.sql("test.csv",dbname=NULL))             

##    user  system elapsed 
##   12.49    0.09   12.69

# sqldf as on SO

f <- file("test.csv")
system.time(SQLf <- sqldf("select * from f", dbname = tempfile(), file.format = list(header = T, row.names = F)))

##    user  system elapsed 
##   10.21    0.47   10.73

Ff / FFDF

 require(ff)

 system.time(FFDF <- read.csv.ffdf(file="test.csv",nrows=n))   
 ##    user  system elapsed 
 ##   10.85    0.10   10.99

总而言之:

##    user  system elapsed  Method
##   24.71    0.15   25.42  read.csv (first time)
##   17.85    0.07   17.98  read.csv (second time)
##   10.20    0.03   10.32  Optimized read.table
##    3.12    0.01    3.22  fread
##   12.49    0.09   12.69  sqldf
##   10.21    0.47   10.73  sqldf on SO
##   10.85    0.10   10.99  ffdf

一个小的附加点值得一提。如果你有一个非常大的文件,你可以在运行中计算行数(如果没有头文件)使用(其中bedGraph是你的文件在你的工作目录中的名称):

>numRow=as.integer(system(paste("wc -l", bedGraph, "| sed 's/[^0-9.]*\\([0-9.]*\\).*/\\1/'"), intern=T))

你可以在read。csv, read中使用。表格

>system.time((BG=read.table(bedGraph, nrows=numRow, col.names=c('chr', 'start', 'end', 'score'),colClasses=c('character', rep('integer',3)))))
   user  system elapsed 
 25.877   0.887  26.752 
>object.size(BG)
203949432 bytes

上面这些我都试过了,[1]做得最好。我只有8gb的内存

循环20个文件,每个5gb, 7列:

read_fwf(arquivos[i],col_types = "ccccccc",fwf_cols(cnpj = c(4,17), nome = c(19,168), cpf = c(169,183), fantasia = c(169,223), sit.cadastral = c(224,225), dt.sitcadastral = c(226,233), cnae = c(376,382)))