Недавно мы писали приложение на Shiny, где нужно было использовать очень большой блок данных (dataframe). Это непосредственно влияло на время запуска приложения, поэтому пришлось рассмотреть ряд способов чтения данных из файлов в R (в нашем случае это были csv-файлы, предоставленные заказчиком) и определить лучший.
Цель этой заметки — сравнить:
Для начала сгенерируем некоторые случайные данные:
и сохраним файлы на диске, чтобы оценить время загрузки. Кроме формата
Теперь проверим размеры файлов:
Как видим, оба формата файлов, и
Для сравнения времени чтения в 10 раундах использовалась библиотека
И победитель…
Использование
Что касается чтения из формата
В нашем случае решили работать с
Окончательная последовательность действий была такой:
Первые две задачи были выполнены единожды и вне контекста приложения на Shiny.
Есть еще один интересный тест производительности по считыванию файлов в R. К сожалению, если использовать функции, указанные в статье, вы получите объекты строкового типа, и придется выполнить какую-то обработку строковых данных, прежде чем можно будет работать с наиболее широко и часто применяемым dataframe.
Цель этой заметки — сравнить:
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.
Поделиться с друзьями
Комментарии (5)
kxx
16.04.2017 18:14Да и сам пакет data.table хорошо оптимизирован. Без проблем позволяет ворочать гигабайтами данных в оперативной памяти.
jzha
16.04.2017 23:32Есть пакет
fst
для быстрой сериализации данных.
Бенчмарки авторов этого пакета показывают, чтоfst
значительно быстрееfeather
.
Но, вообще говоря, такое преимущество зависит от используемых данных, так как "магия"fst
основана на компрессии данных.
vladob
17.04.2017 06:02Я сам не люблю лишних зависимостей (библиотек, например), пытаюсь обходиться собственными силами, точнее — силами R и системы.
R распознает и сам умеет читать/писать csv и прочие txt в/из зипованных/-нные, например gz. БодрЕе в результате получается в большинстве случаев, не говоря уже о месте на диске.
Ares_ekb
Есть ещё прикольный формат — parquet. В нём данные хранятся колонками, а не строками. Размер где-то раза в 4 меньше, чем у CSV. Скорость чтения/записи существенно выше. Если нужна только часть колонок, то ещё быстрее.
Roman_Kh
feather
тоже колоночный формат. И читать отдельные колонки также умеет.