Недавно мы писали приложение на Shiny, где нужно было использовать очень большой блок данных (dataframe). Это непосредственно влияло на время запуска приложения, поэтому пришлось рассмотреть ряд способов чтения данных из файлов в R (в нашем случае это были csv-файлы, предоставленные заказчиком) и определить лучший.
Цель этой заметки — сравнить:
read.csv
изutils
— стандартный способ чтения csv-файлов в Rread_csv
изreadr
, который в RStudio заменил предыдущий методload
иreadRDS
изbase
, и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
.
Окончательная последовательность действий была такой:
- чтение
csv
-файла, предоставленного заказчиком, с помощьюfread
, - запись этого файла в
feather
черезwrite_feather
, и - загрузка
feather
-файла при запуске приложения, используяread_feather
.
Первые две задачи были выполнены единожды и вне контекста приложения на Shiny.
Есть еще один интересный тест производительности по считыванию файлов в R. К сожалению, если использовать функции, указанные в статье, вы получите объекты строкового типа, и придется выполнить какую-то обработку строковых данных, прежде чем можно будет работать с наиболее широко и часто применяемым dataframe.
Автор: Анна Каплун