为什么read_csv的结果比read.csv的结果大?

Why are the results of read_csv larger than those of read.csv?

我在项目中导入许多(> 300).csv 文件,我偶然发现了一个非常奇怪的事件。

比较 read_csvread.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% 可能不是那么多,但仍然是 23 MB,我仍然想知道为什么它们不同。此外,这两个值都小于 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 存储相同数据所用的 space 比旧 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.csvread_csv.

恕我直言 data.table 没有得到应有的一半爱,最好的 all-round 性能包和非常简洁的语法。 following vignettes 应该会让您快速上路,相信我,这是值得的。

为了进一步提高性能 Rfast 包含许多 Rcpp 流行函数和问题的实现,例如 rowSort()


编辑:fread 的速度是由于在 C-code 级别进行的优化,涉及使用内存映射指针和 coerce-as-you-go 技术,坦率地说,这超出了我的知识范围解释。 This post 包含作者 Matt Dowle 的一些解释,以及他与 dplyr 的作者 Hadley Wickham 之间的一段有趣但简短的讨论。