[Перевод] Быстрая загрузка данных из файлов в R


habralogo.jpg
Недавно мы писали приложение на Shiny, где нужно было использовать очень большой блок данных (dataframe). Это непосредственно влияло на время запуска приложения, поэтому пришлось рассмотреть ряд способов чтения данных из файлов в R (в нашем случае это были csv-файлы, предоставленные заказчиком) и определить лучший.

Цель этой заметки — сравнить:

  1. read.csv из utils — стандартный способ чтения csv-файлов в R
  2. read_csv из readr, который в RStudio заменил предыдущий метод
  3. load и readRDS из base, и
  4. read_feather из feather и fread из data.table.


Данные


Для начала сгенерируем некоторые случайные данные
set.seed(123)
df <- data.frame(replicate(10, sample(0:2000, 15 * 10^5, rep = TRUE)),
                 replicate(10, stringi::stri_rand_strings(1000, 5)))

и сохраним файлы на диске, чтобы оценить время загрузки. Кроме формата csv, еще понадобятся файлы feather, RDS и Rdata.
path_csv <- '../assets/data/fast_load/df.csv'
path_feather <- '../assets/data/fast_load/df.feather'
path_rdata <- '../assets/data/fast_load/df.RData'
path_rds <- '../assets/data/fast_load/df.rds'

library(feather)
library(data.table)

write.csv(df, file = path_csv, row.names = F)
write_feather(df, path_feather)
save(df, file = path_rdata)
saveRDS(df, path_rds)

Теперь проверим размеры файлов:
files <- c('../assets/data/fast_load/df.csv', '../assets/data/fast_load/df.feather', '../assets/data/fast_load/df.RData', '../assets/data/fast_load/df.rds')
info <- file.info(files)
info$size_mb <- info$size/(1024 * 1024) 
print(subset(info, select=c("size_mb")))

##                                       size_mb
## ../assets/data/fast_load/df.csv     1780.3005
## ../assets/data/fast_load/df.feather 1145.2881
## ../assets/data/fast_load/df.RData    285.4836
## ../assets/data/fast_load/df.rds      285.4837

Как видим, оба формата файлов, и csv, и feather, занимают гораздо больше места на диске. Csv — в 6 раз, а feather — более, чем в 4 раз больше RDS и RData.

Тест производительности


Для сравнения времени чтения в 10 раундах использовалась библиотека microbenchmark. Методы:
  • utils: read.csv
  • readr: read_csv
  • data.table: fread
  • base: load
  • base: readRDS
  • feather: read_feather

library(microbenchmark)
benchmark <- microbenchmark(readCSV = utils::read.csv(path_csv),
               readrCSV = readr::read_csv(path_csv, progress = F),
               fread = data.table::fread(path_csv, showProgress = F),
               loadRdata = base::load(path_rdata),
               readRds = base::readRDS(path_rds),
               readFeather = feather::read_feather(path_feather), times = 10)
print(benchmark, signif = 2)

##Unit: seconds
##        expr   min    lq       mean median    uq   max neval
##     readCSV 200.0 200.0 211.187125  210.0 220.0 240.0    10
##    readrCSV  27.0  28.0  29.770890   29.0  32.0  33.0    10
##       fread  15.0  16.0  17.250016   17.0  17.0  22.0    10
##   loadRdata   4.4   4.7   5.018918    4.8   5.5   5.9    10
##     readRds   4.6   4.7   5.053674    5.1   5.3   5.6    10
## readFeather   1.5   1.8   2.988021    3.4   3.6   4.1    10

И победительfeather! Однако, использование feather предполагает предварительную конвертацию файлов в этот формат.

Использование load или readRDS может улучшить производительность (второе и третье место с точки зрения скорости), хранение маленького / сжатого файла — тоже преимущество. В обоих случаях сначала придется сконвертировать ваш файл в соответствующий формат.

Что касается чтения из формата csv, fread значительно выигрывает у read_csv и read.csv, и соответственно, является лучшим вариантом для чтения из csv-файла.

В нашем случае решили работать с feather-файлом, поскольку конвертация из csv в этот формат была однократной, и у нас не было строгого ограничения на размер файлов, потому мы не рассматривали форматы Rds или RData.

Окончательная последовательность действий была такой:

  1. чтение csv-файла, предоставленного заказчиком, с помощью fread,
  2. запись этого файла в feather через write_feather, и
  3. загрузка feather-файла при запуске приложения, используя read_feather.

Первые две задачи были выполнены единожды и вне контекста приложения на Shiny.

Есть еще один интересный тест производительности по считыванию файлов в R. К сожалению, если использовать функции, указанные в статье, вы получите объекты строкового типа, и придется выполнить какую-то обработку строковых данных, прежде чем можно будет работать с наиболее широко и часто применяемым dataframe.

Комментарии (1)

  • 16 апреля 2017 в 16:27

    0

    Есть ещё прикольный формат — parquet. В нём данные хранятся колонками, а не строками. Размер где-то раза в 4 меньше, чем у CSV. Скорость чтения/записи существенно выше. Если нужна только часть колонок, то ещё быстрее.

© Habrahabr.ru