我在一个项目中导入了许多(>300(.csv文件,我偶然发现了一个非常奇怪的事情。
当比较read_csv
和read.csv
的结果时,在大小上存在显著差异。Windows列出的所有文件的文件大小为~442 MB。
使用readr
library(tidyverse)
datadir <- "Z:\data\attachments"
list_of_files <- list.files(path = datadir, full.names = TRUE)
readr_data <- lapply(list_of_files, function(x) {
read_csv(x, col_types = cols())
})
object.size(readr_data)
#> 416698080 bytes
str(readr_data[1])
#> List of 1
#> $ : tibble [2,123 x 80] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
使用base
方法
base_data <- lapply(list_of_files, function(x) {
read.csv(x)
})
object.size(base_data)
#> 393094616 bytes
str(base_data[1])
#> List of 1
#> $ :'data.frame': 2123 obs. of 80 variables:
# Compare size
object.size(readr_data) / object.size(base_data) * 100
#> 106 bytes
现在6%可能没有那么多,但仍然是23MB,我仍然感兴趣的是为什么这些不同。此外,这两个都比Windows报告的要小。
为什么列表大小不同,这重要吗?
编辑:显然有些课程是不同的。我用了这个方法:
readr_class <- sapply(readr_data[[1]], class)
base_class <- sapply(base_data[[1]], class)
result <- data.frame(readr_class, base_class)
这些就是区别:
readr_class base_class
var1 numeric integer
var2 numeric integer
var3 numeric integer
var4 character integer
选择正确的函数对于编写高效的代码当然非常重要。不同函数和包中的优化程度将影响对象的存储方式、大小以及在其上运行的操作速度。请考虑以下内容。
library(data.table)
a <- c(1:1000000)
b <- rnorm(1000000)
mat <- as.matrix(cbind(a, b))
df <- data.frame(a, b)
dt <- data.table::as.data.table(mat)
cat(paste0("Matrix size: ",object.size(mat), "ndf size: ", object.size(df), " (",round(object.size(df)/object.size(mat),2) ,")ndt size: ", object.size(dt), " (",round(object.size(dt)/object.size(mat),2),")" ))
Matrix size: 16000568
df size: 12000848 (0.75)
dt size: 4001152 (0.25)
因此,在这里您已经看到data.table
存储相同的数据所使用的空间是旧matrix
的4倍,是data.frame
的3倍。现在关于操作速度:
> microbenchmark(df[df$a*df$b>500,], mat[mat[,1]*mat[,2]>500,], dt[a*b>500])
Unit: milliseconds
expr min lq mean median uq max neval
df[df$a * df$b > 500, ] 23.766201 24.136201 26.49715 24.34380 30.243300 32.7245 100
mat[mat[, 1] * mat[, 2] > 500, ] 13.010000 13.146301 17.18246 13.41555 20.105450 117.9497 100
dt[a * b > 500] 8.502102 8.644001 10.90873 8.72690 8.879352 112.7840 100
data.table
在data.frame
上比base
快1.7倍,比使用matrix
快2.5倍。
这还不是全部,对于几乎任何CSV导入,使用data.table::fread
都会改变你的生活。尝试一下,不要使用read.csv
或read_csv
。
IMHOdata.table
没有得到应有的一半的喜爱,它是性能最好的全方位软件包,语法非常简洁。下面的小插曲应该会让你很快走上正轨,相信我,这是值得的
为了进一步提高性能,Rfast
包含许多流行功能和问题的Rcpp
实现,例如rowSort()
。
EDIT:fread
的速度是由于在C代码级别进行的优化,包括使用指针进行内存映射,以及强制现用技术,坦率地说,我无法解释这些技术。这篇文章包含了作者Matt Dowle的一些解释,以及他与dplyr
的作者Hadley Wickham之间的一段有趣的(如果简短的话(讨论。