提高write.table的性能
我有一个提高write.table的性能,r,R,我有一个data.frame,我想把它写出来。mydata.frame的维度是256行乘65536列。除了write.csv,还有什么更快的替代方案 如果您的所有列都属于同一类,则在写入之前将其转换为矩阵,这样可以将速度提高近6倍。此外,您还可以研究使用包MASS中的write.matrix()。也许我没有正确设置一些东西: #Fake data m <- matrix(runif(256*65536), nrow = 256) #AS a data.frame system.time(w
data.frame
,我想把它写出来。mydata.frame
的维度是256行乘65536列。除了write.csv
,还有什么更快的替代方案 如果您的所有列都属于同一类,则在写入之前将其转换为矩阵,这样可以将速度提高近6倍。此外,您还可以研究使用包MASS
中的write.matrix()。也许我没有正确设置一些东西:
#Fake data
m <- matrix(runif(256*65536), nrow = 256)
#AS a data.frame
system.time(write.csv(as.data.frame(m), "dataframe.csv"))
#----------
# user system elapsed
# 319.53 13.65 333.76
#As a matrix
system.time(write.csv(m, "matrix.csv"))
#----------
# user system elapsed
# 52.43 0.88 53.59
#Using write.matrix()
require(MASS)
system.time(write.matrix(m, "writematrix.csv"))
#----------
# user system elapsed
# 113.58 59.12 172.75
因此,这并不是什么大问题,也不像下面的评论所认为的那样歪曲信息。如果您仍然不确信在大数据帧上使用write.csv()
是一个坏主意,请参阅注释下的手册:
write.table can be slow for data frames with large numbers (hundreds or more) of
columns: this is inevitable as each column could be of a different class and so must be
handled separately. If they are all of the same class, consider using a matrix instead.
最后,考虑到如果你仍在睡眠中超速保存,则移动到本地RDATA对象
system.time(save(m2, file = "thisisfast.RData"))
# user system elapsed
# 21.67 0.12 21.81
data.table::fwrite()
由Otto Seiskari提供,版本为1.9.8+。Matt在顶部做了额外的增强(包括并行化),并对此进行了描述。请在网上报告任何问题
首先,这里比较了@chase在上面使用的相同维度(即大量列:65000列(!)x256行),以及fwrite
和write\u feather
,因此我们在机器之间有一定的一致性。注意compress=FALSE
在基数R中造成的巨大差异
# -----------------------------------------------------------------------------
# function | object type | output type | compress= | Runtime | File size |
# -----------------------------------------------------------------------------
# save | matrix | binary | FALSE | 0.3s | 134MB |
# save | data.frame | binary | FALSE | 0.4s | 135MB |
# feather | data.frame | binary | FALSE | 0.4s | 139MB |
# fwrite | data.table | csv | FALSE | 1.0s | 302MB |
# save | matrix | binary | TRUE | 17.9s | 89MB |
# save | data.frame | binary | TRUE | 18.1s | 89MB |
# write.csv | matrix | csv | FALSE | 21.7s | 302MB |
# write.csv | data.frame | csv | FALSE | 121.3s | 302MB |
请注意,fwrite()
并行运行。这里显示的计时是在13英寸Macbook Pro上进行的,它有2个内核和1个线程/内核(通过超线程增加2个虚拟线程)、512GB SSD、256KB/内核二级缓存和4MB四级缓存。根据您的系统规格,YMMV
我还根据相对更可能(和更大)的数据重新运行基准:
library(data.table)
NN <- 5e6 # at this number of rows, the .csv output is ~800Mb on my machine
set.seed(51423)
DT <- data.table(
str1 = sample(sprintf("%010d",1:NN)), #ID field 1
str2 = sample(sprintf("%09d",1:NN)), #ID field 2
# varying length string field--think names/addresses, etc.
str3 = replicate(NN,paste0(sample(LETTERS,sample(10:30,1),T), collapse="")),
# factor-like string field with 50 "levels"
str4 = sprintf("%05d",sample(sample(1e5,50),NN,T)),
# factor-like string field with 17 levels, varying length
str5 = sample(replicate(17,paste0(sample(LETTERS, sample(15:25,1),T),
collapse="")),NN,T),
# lognormally distributed numeric
num1 = round(exp(rnorm(NN,mean=6.5,sd=1.5)),2),
# 3 binary strings
str6 = sample(c("Y","N"),NN,T),
str7 = sample(c("M","F"),NN,T),
str8 = sample(c("B","W"),NN,T),
# right-skewed (integer type)
int1 = as.integer(ceiling(rexp(NN))),
num2 = round(exp(rnorm(NN,mean=6,sd=1.5)),2),
# lognormal numeric that can be positive or negative
num3 = (-1)^sample(2,NN,T)*round(exp(rnorm(NN,mean=6,sd=1.5)),2))
# -------------------------------------------------------------------------------
# function | object | out | other args | Runtime | File size |
# -------------------------------------------------------------------------------
# fwrite | data.table | csv | quote = FALSE | 1.7s | 523.2MB |
# fwrite | data.frame | csv | quote = FALSE | 1.7s | 523.2MB |
# feather | data.frame | bin | no compression | 3.3s | 635.3MB |
# save | data.frame | bin | compress = FALSE | 12.0s | 795.3MB |
# write.csv | data.frame | csv | row.names = FALSE | 28.7s | 493.7MB |
# save | data.frame | bin | compress = TRUE | 48.1s | 190.3MB |
# -------------------------------------------------------------------------------
另一个选项是使用文件格式
df <- as.data.frame(matrix(runif(256*65536), nrow = 256))
system.time(feather::write_feather(df, "df.feather"))
#> user system elapsed
#> 0.237 0.355 0.617
现在,这是一个有点不公平的比较,因为saveRDS
的默认值是压缩数据,而这里的数据是不可压缩的,因为它是完全随机的。关闭压缩功能会大大加快存储速度:
system.time(saveRDS(df, "df.rds", compress = FALSE))
#> user system elapsed
#> 0.181 0.247 0.473
事实上,它现在比羽毛稍微快一点。那为什么要用羽毛呢?嗯,它通常比readRDS()
要快,而且与读取数据的次数相比,写入数据的次数相对较少
system.time(readRDS("df.rds"))
#> user system elapsed
#> 0.198 0.090 0.287
system.time(feather::read_feather("df.feather"))
#> user system elapsed
#> 0.125 0.060 0.185
您还可以尝试“readr”包的read_rds(与data.table::fread比较)和write_rds(与data.table::fwrite比较)
下面是我的数据集中的一个简单示例 (1133行和429499列):
写入数据集
fwrite(rankp2,file=“rankp2_429499.txt”,col.names=T,row.names=F,quote=F,sep=“\T”)
write_rds(rankp2,“rankp2_429499.rds”)
读取数据集(1133行和429499列)
system.time(fread(“rankp2_429499.txt”,sep=“\t”,header=t,fill=TRUE))
用户系统运行时间
42.391 0.526 42.949
system.time(读取rds(“rankp2\u 429499.rds”))
用户系统运行时间
2.157 0.388 2.547
希望有帮助。
用于快速读取和写入数据文件的最新选项是fst
以二进制格式生成文件
使用write.fst(dat,“file.fst”,compress=0)
,其中compress
可以从0(无压缩)变为100(最大压缩)。可以使用dat=read.fst(“file.fst”)
将数据读回R。根据中列出的计时,它比feather
、data.table
和base RreadRDS
和writers
快
软件包开发网站警告说,fst
数据格式仍在发展中,因此不应将fst
用于长期数据存储。我认为您应该使用fwrite()
速度快得多,对我帮助很大:
fwrite(x, file = "", append = FALSE, quote = "auto",
sep = ",", sep2 = c("","|",""),
eol = if (.Platform$OS.type=="windows") "\r\n" else "\n",
na = "", dec = ".", row.names = FALSE, col.names = TRUE,
qmethod = c("double","escape"),
logical01 = getOption("datatable.logical01", FALSE), # due to change to TRUE; see NEWS
logicalAsInt = logical01, # deprecated
dateTimeAs = c("ISO","squash","epoch","write.csv"),
buffMB = 8L, nThread = getDTthreads(),
showProgress = interactive(),
verbose = getOption("datatable.verbose", FALSE))
或者使用更快的硬盘,或者如果您的数据可以转换为矩阵,请使用write
。但当我第一次将其导入R use read.table时,它会自动使用dataframe,因此,在我完成计算后,我需要使用as.matrix?您需要将其写为CSV,还是可以将其保存为RData对象或其他压缩形式?我希望输出的文件看起来像一个矩阵,它将有单独的列和行。@lolibility-我想我的问题更多的是为什么需要它看起来像一个矩阵?你是打算在另一个程序中打开它,还是将它输入到其他程序中?或者,您只需要保存,以便以后可以在R中提取它。正如我在下面所展示的,原生R对象可以更快地保存并占用更少的空间。在下面的例子中,CSV文件需要约275MB,而RData对象需要约80MB。这有点不公平的比较。。。as.data.frame需要相当长的时间。此外,OP拥有的数据已经在data.frame中。@John-这很好,尽管与使用write.csv()
和朋友在data.frame
与matrix
上的开销相比,as.data.frame
的相对开销可以忽略不计。我知道这要少一些,但是最好有可能被接受的答案,而不是让天真的读者去回答这个问题。@John-是的,我完全同意。谢谢你朝着正确的方向轻推。老实说,我只是草率行事,但我想给出的不仅仅是RTFM
的回应。另外,as.data.frame()
的开销也会增加,因为在最终的system.time(save(…)
中,添加compress=FALSE
要快得多。在我的机器上是14秒,而不是0.2秒。有关想要测试它的人的要点,请参阅。FWIW,fwrite对于CSV来说速度很快,但与feather不在同一级别。请注意saveRDS
需要compress=FALSE
,feather
很好,但与原始问题无关。因为它是二进制格式…@DmitriySeliva
system.time(saveRDS(df, "df.rds"))
#> user system elapsed
#> 17.363 0.307 17.856
system.time(saveRDS(df, "df.rds", compress = FALSE))
#> user system elapsed
#> 0.181 0.247 0.473
system.time(readRDS("df.rds"))
#> user system elapsed
#> 0.198 0.090 0.287
system.time(feather::read_feather("df.feather"))
#> user system elapsed
#> 0.125 0.060 0.185
fwrite(x, file = "", append = FALSE, quote = "auto",
sep = ",", sep2 = c("","|",""),
eol = if (.Platform$OS.type=="windows") "\r\n" else "\n",
na = "", dec = ".", row.names = FALSE, col.names = TRUE,
qmethod = c("double","escape"),
logical01 = getOption("datatable.logical01", FALSE), # due to change to TRUE; see NEWS
logicalAsInt = logical01, # deprecated
dateTimeAs = c("ISO","squash","epoch","write.csv"),
buffMB = 8L, nThread = getDTthreads(),
showProgress = interactive(),
verbose = getOption("datatable.verbose", FALSE))