Изменения

R:Оптимизация/Импорт данных

3270 байтов добавлено, 13:35, 6 апреля 2014
м
Нет описания правки
== Импорт CSV ==
=== Функция <code>read.table()</code> ===
Для импорта файлов CSV в R предусмотрена функция <code>read.table()</code> и функци-обёртка (wrapper) <code>read.csv()</code>. С точки зрения скорости работы, параметры функции <code>read.table()</code>, заданные по умолчанию, не являются оптимальными. Приведём несколько рекомендаций по использованию функции <code>read.table()</code>:
Создадим таблицу данных содержащую <math>10^{6}</math> строк и 6 столбцов:
{{r-code|code=<nowiki>>set.seed(123) # начальная точка для генератора случайных чисел для воспроизводимости результатов> N <- 10^6L # задаём количество наблюдений
> DF <- data.frame(a = sample(1:10^3L, N, replace = TRUE),
+ b = sample(1:10^3L, N, replace = TRUE),
{{r-code|code=<nowiki>> microbenchmark(defaults = read.table(tmp.csv, sep = ";", header = TRUE),
+ ompimize = read.table(tmp.csv, sep = ";", header = TRUE, nrows = N, comment.char = "",+ colClasses = c("integer", "integer", "factor", "numeric", "numeric", "numeric"),+ nrows = N, comment.char = ""))
Unit: seconds
expr min lq median uq max neval defaults 63.204 6951 4.673 043 74.024 7068 4.253 10169 4.996 850 100 ompimize 2.833 852 2.858 927 2.921 3931 2.161 943 3.202 631 100</nowiki>}} Отметим, что чтение файла осуществлялось непосредственно из оперативной памяти, т.к. файл находился в файловой системе [http://ru.wikipedia.org/wiki/Tmpfs <code>tmpfs</code>].
Значения для аргумента <code>colClasses</code> мы получили ранее с помощью команды <code>sapply(DF, class)</code>.
Таким образом, по результатам сравнения, можем заключить, что указание специфических аргументов функции <code>read.table()</code> позволяет существенно ускорить процесс импорта данных в формате CSV.
=== Функция <code>scan</code> === Проведя [[R:Профилирование кода|профилирование]] выполнения функции <code>read.table()</code> мы получили следующие результаты: {{r-code|code=<code>> tmp.log <- tempfile(pattern ="prof-", fileext =".log")> source("http://git.psylab.info/r-scripts/raw/master/proftable.R")> Rprof(tmp.log, interval = 0.01)> DF <- read.table(tmp.csv, sep = ";", header = TRUE)> Rprof(NULL)> proftable(tmp.log) Calls: PctTime Call 90.86 scan 7.59 type.convert > .External2 1.55  Files:/tmp/RtmpAvhCfO/file23b65745e7ba.R Parent Call: read.table  Total Time: 7.11 seconds Percent of run time represented: 100%</code>}} В данном выводе хорошо видно, что 90% времени затрачено на чтение файла с помощью функции <code>scan()</code>. Мы задались вопросом: а возможно ли получить требуемый результат, пользуясь только функцией и <code>scan()</code> и приведёт ли это к увеличению производительности. После некоторых экспериментов нам подобрать команду, приводящую к нужному результату: {{r-code|code=<code>data.frame(scan(tmp.csv, what = list(a = integer(0), b = integer(0), c = character(0), d = numeric(0), e = numeric(0), f = numeric(0)), nmax = N, sep = ";", quote = "\"", multi.line = FALSE, skip = 1L, quiet = TRUE))</code>}} Ниже приведены результаты сравнения работы функций <code>read.table()</code> и <code>scan()</code>: {{r-code|code=<nowiki>> microbenchmark(defaults = read.table(tmp.csv, sep = ";", header = TRUE),+ ompimize = read.table(tmp.csv, sep = ";", header = TRUE, nrows = N, comment.char = "", + colClasses = c("integer", "integer", "factor", "numeric", "numeric", "numeric")),+ scan = data.frame(scan(tmp.csv, nmax = N, sep = ";", quote = "\"", multi.line = FALSE, skip = 1L, quiet = TRUE,+ what = list(a = integer(0), b = integer(0), c = character(0), d = numeric(0), e = numeric(0), f = numeric(0)))))Unit: seconds expr min lq median uq max neval defaults 3.948 4.037 4.109 4.220 4.757 100 ompimize 2.851 2.863 2.931 3.005 3.686 100 scan 2.970 2.985 3.058 3.653 3.822 100</nowiki>}} Как видим, функций <code>scan()</code> работает быстрее <code>read.table()</code> с параметрами по умолчанию и может сравниться по скорости работы с <code>read.table()</code> с оптимизированными аргументами.
=== Функция <code>fread()</code> ===
Пакет {{r-package|data.table}}, помимо прочего, включает в себя функцию для чтения csv-файлов - <code>fread()</code>. Стоит отметить, что полученная в результате импорта переменная будет иметь класс <code>data.table</code>, что предполагает определённую специфику работы с ней<ref>Синтаксис работы с классом <code>data.table</code> отличен от синтаксиса работы с матрицами и таблицами данных в R.</ref>.
{{r-code|code=<nowiki>> library(data.table)
> microbenchmark(defaults = read.table(tmp.csv, sep = ";", header = TRUE),
+ ompimize = read.table(tmp.csv, sep = ";", header = TRUE, nrows = N, comment.char = "",+ colClasses = c("integer", "integer", "factor", "numeric", "numeric", "numeric"),+ nrows = N, comment.char = "", quote=""),+ data.table fread = fread(tmp.csv))
Unit: milliseconds
expr min lq median uq max neval defaults 53443957.4 8063.6 8513.6 88535 4049.0 13602 4066 4166.0 3 4797 100 ompimize 2839.3 28562844.9 28962853.7 32036 2928 2932.7 3573.5 0 3557 100 fread data532.table 2 526533.6 528.2 4 534 535.9 5 578.2 932.3 616 100</nowiki>}}
Таким образом, функция <code>fread()</code> является более быстрым и более удобным (за счёт автоматического определения входных параметров) инструментом по сравнению со штатной функцией <code>read.table()</code> (даже при использовании оптимальных параметров).