【问题标题】:base R faster than readr for reading multiple CSV files在读取多个 CSV 文件时,base R 比 readr 更快
【发布时间】:2017-10-17 10:18:58
【问题描述】:

有很多关于如何读取多个 CSV 并将它们绑定到一个数据框的文档。我有 5000 多个 CSV 文件需要读取并绑定到一个数据结构中。

我特别关注了这里的讨论:Issue in Loading multiple .csv files into single dataframe in R using rbind

奇怪的是,base R 比我尝试过的任何其他解决方案都要快。

这是我的 CSV 的样子:

> head(PT)
  Line          Timestamp       Lane.01 Lane.02 Lane.03 Lane.04 Lane.05 Lane.06 Lane.07 Lane.08
1    PL1    05-Jan-16 07:17:36      NA      NA      NA      NA      NA      NA      NA      NA
2    PL1    05-Jan-16 07:22:38      NA      NA      NA      NA      NA      NA      NA      NA
3    PL1    05-Jan-16 07:27:41      NA      NA      NA      NA      NA      NA      NA      NA
4    PL1    05-Jan-16 07:32:43    9.98   10.36   10.41   10.16   10.10    9.97   10.07    9.59
5    PL1    05-Jan-16 07:37:45    9.65    8.87    9.88    9.86    8.85    8.75    9.19    8.51
6    PL1    05-Jan-16 07:42:47    9.14    8.98    9.29    9.04    9.01    9.06    9.12    9.08

我创建了三种读取和绑定数据的方法。这些文件位于一个单独的目录中,我将其定义为:

dataPath <- "data"
PTfiles <- list.files(path=dataPath, full.names = TRUE)

方法一:基础R

classes <- c("factor", "character", rep("numeric",8))

# build function to load data
load_data <- function(dataPath, classes) { 
   tables <- lapply(PTfiles, read.csv, colClasses=classes, na.strings=c("NA", ""))
   do.call(rbind, tables)
}

#clock
method1 <- system.time(
   PT <- load_data(path, classes)
)

方法二: read_csv 在这种情况下,我创建了一个包装函数供 read_csv 使用

#create wrapper function for read_csv
read_csv.wrap <- function(x) { read_csv(x, skip = 1, na=c("NA", ""),
                      col_names = c("tool", "timestamp", paste("lane", 1:8, sep="")),
                      col_types = 
                         cols(
                            tool = col_character(),
                            timestamp = col_character(),
                            lane1 = col_double(),
                            lane2 = col_double(),
                            lane3 = col_double(),
                            lane4 = col_double(),
                            lane5 = col_double(),
                            lane6 = col_double(),
                            lane7 = col_double(),
                            lane8 = col_double()
                           )
                     )
}

##
# Same as method 1, just uses read_csv instead of read.csv

load_data2 <- function(dataPath) { 
   tables <- lapply(PTfiles, read_csv.wrap)
   do.call(rbind, tables)
}

#clock
method2 <- system.time(
   PT2 <- load_data2(path)
)

方法三: read_csv + dplyr::bind_rows

load_data3 <- function(dataPath) { 
   tables <- lapply(PTfiles, read_csv.wrap)
   dplyr::bind_rows(tables)
}

#clock
method3 <- system.time(
   PT3 <- load_data3(path)
)

我想不通的是,为什么 read_csv 和 dplyr 方法在过去应该更快时会更慢。 CPU时间减少了,但是为什么经过的时间(文件系统)会增加?这是怎么回事?

编辑 - 我按照 cmets 中的建议添加了 data.table 方法

方法四 data.table

library(data.table)

load_data4 <- function(dataPath){
   tables <- lapply(PTfiles, fread)
   rbindlist(tables)
}

method4 <- system.time(
   PT4 <- load_data4(path)
)

从 CPU 的角度来看,data.table 方法是最快的。但问题仍然在于 read_csv 方法发生了什么,这使得它们变得如此缓慢。

> rbind(method1, method2, method3, method4)
        user.self sys.self elapsed
method1      0.56     0.39    1.35
method2      0.42     1.98   13.96
method3      0.36     2.25   14.69
method4      0.34     0.67    1.74

【问题讨论】:

  • 我觉得data.table::fread()是最快的
  • 后跟data.table::rbindlist() 将它们粘合在一起。
  • 我在问题中添加了data.table 方法,速度很快。我的问题仍然是为什么 read_csv 方法这么慢。
  • 如果您可以将其确定为一个非常具体、可重复的示例,并使用您愿意共享的单个文件,您可能会发现在 github 上将此作为问题提出来更有效率。如果它是可重现的,Hadley 可能会对与基础 R 的性能差距非常感兴趣。
  • 您是否尝试过指定列类型?我最近看到的另一种有用的方法是通过sergeant 查询本地Apache Drill(参见here)。安装它比上面的工作要多,但一旦安装它就很强大。

标签: r tidyverse readr


【解决方案1】:

我会在终端(Unix)中这样做。我会将所有文件放在同一个文件夹中,然后导航到该文件夹​​(在终端中),使用以下命令仅创建一个 CSV 文件:

cat *.csv > merged_csv_file.csv

关于此方法的一个观察结果是每个文件的标题将显示在观察结果的中间。为了解决这个问题,我建议你这样做:

只从第一个文件中获取标题

head -2 file1.csv > merged_csv_file.csv

然后使用以下命令跳过其他文件的前“X”行,其中“X”是要跳过的行数。

tail -n +3 -q file*.csv >> merged_csv_file.csv

-n +3 使尾部打印行从第 3 行到末尾,-q 告诉它不要打印带有文件名的标题(阅读人),&gt;&gt; 添加到文件中,而不是覆盖它为 >.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-09-26
    • 1970-01-01
    • 2017-02-15
    • 2021-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-16
    相关资源
    最近更新 更多