Reading multiples CSV files using readr

R
data manipulation
Author

Philippe Massicotte

Published

February 15, 2022

If you are beginning in R, chances are that you have used read.csv() to import CSV files into R. While this function works perfectly fine, it can only read one file at a time. Hence, new R programmers often read multiple files successively and combine the data afterward.


# Read all the data files
df1 <- read.csv("file1.csv")
df2 <- read.csv("file2.csv")
df3 <- read.csv("file3.csv")
df4 <- read.csv("file4.csv")
df5 <- read.csv("file5.csv")

# Combine all the data frame together
big_df <- rbind(df1, df2, df3, df4, df5)

Whereas this can work fine if you have only a few files, this can become tedious when the number of files to read increases. A better approach would be to use a list of files and read them at once. For quite a while, I have been using a combination of map_df() from the purrr package.

# Create a vector of file names
files <- c("file1.csv", "file2.csv", "file3.csv", "file4.csv", "file5.csv")

# Read and combine all data files into a single data frame
big_df <- map_df(files, read_csv)

In the release of readr 2.0.0, the read_csv() function can directly take a list of files as input, eliminating the need to use the mad_df() function. Hence, we can now read multiples files as follow:

# Read and combine all data files into a single data frame without using the
# map_df function
big_df <- read_csv(files)

Lights in the night

In this short blog post, I wanted to benchmark the speed difference between map_df(files, read_csv) and read_csv(files). To do it so let’s first generate some data files.

library(nycflights13)

purrr::iwalk(
  split(flights, flights$carrier),
  ~ {
    .x$carrier[[1]]
    data.table::fwrite(.x, glue::glue("/tmp/flights_{.y}.csv"))
  }
)

files <- fs::dir_ls(path = "/tmp", glob = "*flights*csv")
files
#> /tmp/flights_9E.csv /tmp/flights_AA.csv /tmp/flights_AS.csv /tmp/flights_B6.csv 
#> /tmp/flights_DL.csv /tmp/flights_EV.csv /tmp/flights_F9.csv /tmp/flights_FL.csv 
#> /tmp/flights_HA.csv /tmp/flights_MQ.csv /tmp/flights_OO.csv /tmp/flights_UA.csv 
#> /tmp/flights_US.csv /tmp/flights_VX.csv /tmp/flights_WN.csv /tmp/flights_YV.csv

We can look at what the data look like.

read_csv(files[[1]])
#> # A tibble: 18,460 × 19
#>     year month   day dep_time sched_de…¹ dep_d…² arr_t…³ sched…⁴ arr_d…⁵ carrier
#>    <dbl> <dbl> <dbl>    <dbl>      <dbl>   <dbl>   <dbl>   <dbl>   <dbl>   <dbl>
#>  1  2013     1     1      810        810       0    1048    1037      11       9
#>  2  2013     1     1     1451       1500      -9    1634    1636      -2       9
#>  3  2013     1     1     1452       1455      -3    1637    1639      -2       9
#>  4  2013     1     1     1454       1500      -6    1635    1636      -1       9
#>  5  2013     1     1     1507       1515      -8    1651    1656      -5       9
#>  6  2013     1     1     1530       1530       0    1650    1655      -5       9
#>  7  2013     1     1     1546       1540       6    1753    1748       5       9
#>  8  2013     1     1     1550       1550       0    1844    1831      13       9
#>  9  2013     1     1     1552       1600      -8    1749    1757      -8       9
#> 10  2013     1     1     1554       1600      -6    1701    1734     -33       9
#> # … with 18,450 more rows, 9 more variables: flight <dbl>, tailnum <chr>,
#> #   origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
#> #   minute <dbl>, time_hour <dttm>, and abbreviated variable names
#> #   ¹​sched_dep_time, ²​dep_delay, ³​arr_time, ⁴​sched_arr_time, ⁵​arr_delay
#> # ℹ Use `print(n = ...)` to see more rows, and `colnames()` to see all variable names

Now that data files have been successfully created, we can compare the two reading options.

res <- microbenchmark::microbenchmark(
  map_df_read_csv = map_df(files, read_csv, col_types = cols(carrier = col_character())),
  read_csv = read_csv(files, col_types = cols(carrier = col_character())),
  times = 100
)

res
#> Unit: milliseconds
#>             expr      min       lq     mean   median       uq      max neval
#>  map_df_read_csv 413.3536 441.4230 480.7377 497.3756 502.5032 521.7361   100
#>         read_csv 148.1041 153.3014 163.3054 156.3136 161.2407 251.3683   100

autoplot(res)

Using read_csv() directly seems to be much (~two times) faster than the map_df(files, read_csv) combination.

Session info
#> ─ Session info ───────────────────────────────────────────────────────────────────────────────────────────────────────
#>  setting  value
#>  version  R version 4.2.1 (2022-06-23)
#>  os       Ubuntu 22.04 LTS
#>  system   x86_64, linux-gnu
#>  ui       X11
#>  language en_CA:en
#>  collate  en_CA.UTF-8
#>  ctype    en_CA.UTF-8
#>  tz       America/Toronto
#>  date     2022-07-30
#>  pandoc   2.18 @ /usr/lib/rstudio/bin/quarto/bin/tools/ (via rmarkdown)
#> 
#> ─ Packages ───────────────────────────────────────────────────────────────────────────────────────────────────────────
#>  package        * version date (UTC) lib source
#>  assertthat       0.2.1   2019-03-21 [1] RSPM (R 4.2.0)
#>  backports        1.4.1   2021-12-13 [1] RSPM (R 4.2.0)
#>  bit              4.0.4   2020-08-04 [1] RSPM (R 4.2.0)
#>  bit64            4.0.5   2020-08-30 [1] RSPM (R 4.2.0)
#>  broom            1.0.0   2022-07-01 [1] RSPM (R 4.2.0)
#>  cachem           1.0.6   2021-08-19 [1] RSPM (R 4.2.0)
#>  callr            3.7.1   2022-07-13 [1] RSPM (R 4.2.0)
#>  cellranger       1.1.0   2016-07-27 [1] RSPM (R 4.2.0)
#>  cli              3.3.0   2022-04-25 [1] RSPM (R 4.2.0)
#>  codetools        0.2-18  2020-11-04 [2] CRAN (R 4.2.1)
#>  colorspace       2.0-3   2022-02-21 [1] RSPM (R 4.2.0)
#>  crayon           1.5.1   2022-03-26 [1] RSPM (R 4.2.0)
#>  data.table       1.14.2  2021-09-27 [1] RSPM (R 4.2.0)
#>  DBI              1.1.3   2022-06-18 [1] RSPM (R 4.2.0)
#>  dbplyr           2.2.1   2022-06-27 [1] RSPM (R 4.2.0)
#>  devtools         2.4.4   2022-07-20 [1] RSPM (R 4.2.0)
#>  digest           0.6.29  2021-12-01 [1] RSPM (R 4.2.0)
#>  dplyr          * 1.0.9   2022-04-28 [1] RSPM (R 4.2.0)
#>  ellipsis         0.3.2   2021-04-29 [1] RSPM (R 4.2.0)
#>  evaluate         0.15    2022-02-18 [1] RSPM (R 4.2.0)
#>  extrafont        0.18    2022-04-12 [1] RSPM (R 4.2.0)
#>  extrafontdb      1.0     2012-06-11 [1] RSPM (R 4.2.0)
#>  fansi            1.0.3   2022-03-24 [1] RSPM (R 4.2.0)
#>  farver           2.1.1   2022-07-06 [1] RSPM (R 4.2.0)
#>  fastmap          1.1.0   2021-01-25 [1] RSPM (R 4.2.0)
#>  forcats        * 0.5.1   2021-01-27 [1] RSPM (R 4.2.0)
#>  fs               1.5.2   2021-12-08 [1] RSPM (R 4.2.0)
#>  gargle           1.2.0   2021-07-02 [1] RSPM (R 4.2.0)
#>  generics         0.1.3   2022-07-05 [1] RSPM (R 4.2.0)
#>  ggplot2        * 3.3.6   2022-05-03 [1] RSPM (R 4.2.0)
#>  ggpmthemes     * 0.0.2   2022-07-29 [1] Github (pmassicotte/ggpmthemes@993d61e)
#>  glue             1.6.2   2022-02-24 [1] RSPM (R 4.2.0)
#>  googledrive      2.0.0   2021-07-08 [1] RSPM (R 4.2.0)
#>  googlesheets4    1.0.0   2021-07-21 [1] RSPM (R 4.2.0)
#>  gtable           0.3.0   2019-03-25 [1] RSPM (R 4.2.0)
#>  haven            2.5.0   2022-04-15 [1] RSPM (R 4.2.0)
#>  hms              1.1.1   2021-09-26 [1] RSPM (R 4.2.0)
#>  htmltools        0.5.3   2022-07-18 [1] RSPM (R 4.2.0)
#>  htmlwidgets      1.5.4   2021-09-08 [1] RSPM (R 4.2.0)
#>  httpuv           1.6.5   2022-01-05 [1] RSPM (R 4.2.0)
#>  httr             1.4.3   2022-05-04 [1] RSPM (R 4.2.0)
#>  jsonlite         1.8.0   2022-02-22 [1] RSPM (R 4.2.0)
#>  knitr            1.39    2022-04-26 [1] RSPM (R 4.2.0)
#>  later            1.3.0   2021-08-18 [1] CRAN (R 4.2.1)
#>  lifecycle        1.0.1   2021-09-24 [1] RSPM (R 4.2.0)
#>  lubridate        1.8.0   2021-10-07 [1] RSPM (R 4.2.0)
#>  magrittr         2.0.3   2022-03-30 [1] RSPM (R 4.2.0)
#>  memoise          2.0.1   2021-11-26 [1] RSPM (R 4.2.0)
#>  microbenchmark   1.4.9   2021-11-09 [1] CRAN (R 4.2.1)
#>  mime             0.12    2021-09-28 [1] RSPM (R 4.2.0)
#>  miniUI           0.1.1.1 2018-05-18 [1] RSPM (R 4.2.0)
#>  modelr           0.1.8   2020-05-19 [1] RSPM (R 4.2.0)
#>  munsell          0.5.0   2018-06-12 [1] RSPM (R 4.2.0)
#>  nycflights13   * 1.0.2   2021-04-12 [1] CRAN (R 4.2.1)
#>  pillar           1.8.0   2022-07-18 [1] RSPM (R 4.2.0)
#>  pkgbuild         1.3.1   2021-12-20 [1] RSPM (R 4.2.0)
#>  pkgconfig        2.0.3   2019-09-22 [1] RSPM (R 4.2.0)
#>  pkgload          1.3.0   2022-06-27 [1] RSPM (R 4.2.0)
#>  prettyunits      1.1.1   2020-01-24 [1] RSPM (R 4.2.0)
#>  processx         3.7.0   2022-07-07 [1] RSPM (R 4.2.0)
#>  profvis          0.3.7   2020-11-02 [1] RSPM (R 4.2.0)
#>  promises         1.2.0.1 2021-02-11 [1] RSPM (R 4.2.0)
#>  ps               1.7.1   2022-06-18 [1] RSPM (R 4.2.0)
#>  purrr          * 0.3.4   2020-04-17 [1] RSPM (R 4.2.0)
#>  R6               2.5.1   2021-08-19 [1] RSPM (R 4.2.0)
#>  Rcpp             1.0.9   2022-07-08 [1] RSPM (R 4.2.0)
#>  readr          * 2.1.2   2022-01-30 [1] RSPM (R 4.2.0)
#>  readxl           1.4.0   2022-03-28 [1] RSPM (R 4.2.0)
#>  remotes          2.4.2   2021-11-30 [1] CRAN (R 4.2.1)
#>  reprex           2.0.1   2021-08-05 [1] RSPM (R 4.2.0)
#>  rlang            1.0.4   2022-07-12 [1] RSPM (R 4.2.0)
#>  rmarkdown        2.14    2022-04-25 [1] RSPM (R 4.2.0)
#>  rspm             0.1.0.3 2022-07-27 [1] Github (Enchufa2/rspm@ba091ae)
#>  rstudioapi       0.13    2020-11-12 [1] RSPM (R 4.2.0)
#>  Rttf2pt1         1.3.10  2022-02-07 [1] RSPM (R 4.2.0)
#>  rvest            1.0.2   2021-10-16 [1] RSPM (R 4.2.0)
#>  scales           1.2.0   2022-04-13 [1] RSPM (R 4.2.0)
#>  sessioninfo      1.2.2   2021-12-06 [1] RSPM (R 4.2.0)
#>  shiny            1.7.2   2022-07-19 [1] RSPM (R 4.2.0)
#>  stringi          1.7.8   2022-07-11 [1] RSPM (R 4.2.0)
#>  stringr        * 1.4.0   2019-02-10 [1] RSPM (R 4.2.0)
#>  tibble         * 3.1.8   2022-07-22 [1] RSPM (R 4.2.0)
#>  tidyr          * 1.2.0   2022-02-01 [1] RSPM (R 4.2.0)
#>  tidyselect       1.1.2   2022-02-21 [1] RSPM (R 4.2.0)
#>  tidyverse      * 1.3.2   2022-07-18 [1] RSPM (R 4.2.0)
#>  tzdb             0.3.0   2022-03-28 [1] RSPM (R 4.2.0)
#>  urlchecker       1.0.1   2021-11-30 [1] RSPM (R 4.2.0)
#>  usethis          2.1.6   2022-05-25 [1] CRAN (R 4.2.1)
#>  utf8             1.2.2   2021-07-24 [1] RSPM (R 4.2.0)
#>  vctrs            0.4.1   2022-04-13 [1] RSPM (R 4.2.0)
#>  vroom            1.5.7   2021-11-30 [1] RSPM (R 4.2.0)
#>  withr            2.5.0   2022-03-03 [1] RSPM (R 4.2.0)
#>  xfun             0.31    2022-05-10 [1] RSPM (R 4.2.0)
#>  xml2             1.3.3   2021-11-30 [1] RSPM (R 4.2.0)
#>  xtable           1.8-4   2019-04-21 [1] CRAN (R 4.2.1)
#>  yaml             2.3.5   2022-02-21 [1] RSPM (R 4.2.0)
#> 
#>  [1] /home/filoche/R/x86_64-pc-linux-gnu-library/4.2
#>  [2] /opt/R/4.2.1/lib/R/library
#> 
#> ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────