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

WWW


Тема языка R не впервые поднимается в нашем журнале. Подкинем тебе еще пару линков на статьи по теме:
https://xakep.ru/2015/07/23/data-analysis-r-part-1/
https://xakep.ru/2015/04/20/195-learning-r-programming-language/

 

Устанавливаем пакеты

Все необходимое для нашей сегодняшней статьи можно проинсталлить с помощью соответствующих функций:

install.packages("data.table")
install.packages("dplyr")
install.packages("readr")

 

R атакует

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

На словах все просто, но в реальной жизни для формирования «хорошей» и устойчивой модели требуется множество попыток, большинство из которых могут быть абсолютно тупиковыми. Язык R помогает упростить процесс создания такой модели, так как это эффективный инструмент анализа табличных данных. Для работы с ними в R существует встроенный тип данных data.frame и огромное количество алгоритмов и моделей, которые его активно используют. К тому же вся мощь R заключается в возможности расширять базовую функциональность с помощью сторонних пакетов. В момент написания материала их количество в официальном репозитории достигло 8914.

Но, как говорится, нет предела совершенству. Большое количество пакетов позволяют облегчить работу с самим типом данных data.frame. Обычно их цель — упростить синтаксис для выполнения наиболее распространенных задач. Здесь нельзя не вспомнить пакет dplyr, который уже стал стандартом де-факто для работы с data.frame, так как за счет него читаемость и удобство работы с таблицами выросли в разы.

Перейдем от теории к практике и создадим data.frame DF со столбцами a, b и с.

DF <- data.frame(a=sample(1:10, 100, replace = TRUE), # Случайные числа от 1 до 10
                 b=sample(1:5, 100, replace = TRUE),  # Случайные числа от 1 до 5
                 c=100:1)                             # Числа от 100 до 1

Если мы хотим:

  • выбрать только столбцы a и с,
  • отфильтровать строчки, где a = 2 и с > 10,
  • создать новую колонку , равную сумме a и с,
  • записать результат в переменную DF2,

базовый синтаксис на чистом data.frame будет такой:

DF2 <- DF[DF$a == 2 & DF$c > 10, c("a", "c")] # Фильтруем строки и столбцы
DF2$ac <- DF2$a + DF2$c                       # Создаем новую колонку

С помощью dplyr все гораздо нагляднее:

library(dplyr) # Загрузим пакет dplyr
DF2 <- DF %>% select(a, c) %>% filter(a == 2, c > 10) %>% mutate(ac = a + c)

Эти же шаги, но с комментариями:

DF2 <-                          # Результат всего, что справа, записать в DF2
 DF %>%                         # Взять DF и передать дальше (%>%)
   select(a, c) %>%             # Выбрать колонки a и с и передать дальше (%>%)
    filter(a == 2, c > 10) %>%  # Отфильтровать строки и передать дальше (%>%)
     mutate(ac = a + c)         # Добавить колонку ac, равную сумме а и с

Есть и альтернативный подход для работы с таблицами — data.table. Формально data.table — это тоже data.frame, и его можно использовать с существующими функциями и пакетами, которые зачастую ничего не знают о data.table и работают исключительно с data.frame. Этот «улучшенный» data.frame может выполнять многие типовые задачи в несколько раз быстрее своего прародителя. Возникает законный вопрос: где подвох? Этой самой «засадой» в data.table оказывается его синтаксис, который сильно отличается от оригинального. При этом если dplyr с первых же секунд использования делает код легче для понимания, то data.table превращает код в черную магию, и только годы изучения колдовских книг несколько дней практики с data.tableпозволят полностью понять идею нового синтаксиса и принцип упрощения кода.

 

Пробуем data.table

Для работы с data.table необходимо подключить его пакет.

library(data.table) # Подключение пакета

В дальнейших примерах эти вызовы будут опущены и будет считаться, что пакет уже загружен.

Так как данные очень часто загружаются из файлов CSV, то уже на этом этапе data.table может удивлять. Для того чтобы показать более измеримые оценки, возьмем какой-нибудь достаточно большой файл CSV. В качестве примера можно привести данные с одного из последних соревнований на Kaggle. Там ты найдешь тренировочный файл CSV размером в 1,27 Гбайт. Структура файла очень простая:

  • row_id — идентификатор события;
  • x, y — координаты;
  • accuracy — точность;
  • time — время;
  • place_id — идентификатор организации.

Попробуем воспользоваться базовой функцией R — read.csv и измерим время, которое понадобится для загрузки этого файла (для этого обратимся к функции system.time):

system.time(
    train_DF <- read.csv("train.csv")
)

Время выполнения — 461,349 секунды. Достаточно, чтобы сходить за кофе... Даже если в будущем ты не захочешь пользоваться data.table, все равно старайся реже применять встроенные функции чтения CSV. Есть хорошая библиотека readr, где все реализовано гораздо эффективнее, чем в базовых функциях. Посмотрим ее работу на примере и подключим пакет:

library(readr)

Дальше воспользуемся функцией загрузки данных из CSV:

system.time(
    train_DF <- read_csv("train.csv")
)

Время выполнения — 38,067 секунды — значительно быстрее предыдущего результата! Посмотрим, на что способен data.table:

system.time(
    train_DT <- fread("train.csv")
)

Время выполнения — 20,906 секунды, что почти в два раза быстрее, чем в readr, и в двадцать раз быстрее, чем в базовом методе.

В нашем примере разница в скорости загрузки для разных методов получилась достаточно большая. Внутри каждого из используемых методов время линейно зависит от объема файла, но разница в скорости между этими методами сильно зависит от структуры файла (количества и типов столбцов). Ниже указаны тестовые замеры времени загрузки файлов.

Для файла из трех текстовых колонок видно явное преимущество fread:

image
image

Если же считываются не текстовые, а цифровые колонки, то разница между fread и read_csv менее заметна:

image
image

Если после загрузки данных из файла ты собираешься дальше работать с data.table, то fread сразу его возвращает. При других способах загрузки данных будет необходимо сделать data.table из data.frame, хотя это просто:

train_DF                         # Загруженный data.frame
train_DT <- data.table(train_DF) # data.table, созданный из `data.frame`

Большинство оптимизаций по скорости в data.table достигается за счет работы с объектами по ссылке, дополнительные копии объектов в памяти не создаются, а значит, экономится время и ресурсы.

Например, ту же задачу создать data.table из data.frame можно было бы решить одной командой на «прокачку», но надо помнить, что первоначальное значение переменной будет потеряно.

train_DF        # Загруженный data.frame
setDT(train_DF) # Теперь в переменной DF у нас уже содержится data.table

Итак, данные мы загрузили, пора с ними поработать.

Продолжение статьи доступно только подписчикам

Вариант 1. Оформи подписку на «Хакер», чтобы читать все статьи на сайте

Подписка позволит тебе в течение указанного срока читать ВСЕ платные материалы сайта, включая эту статью. Мы принимаем оплату банковскими картами, электронными деньгами и переводами со счетов мобильных операторов. Подробнее о подписке

Вариант 2. Купи одну статью

Заинтересовала статья, но нет возможности оплатить подписку? Тогда этот вариант для тебя! Обрати внимание: этот способ покупки доступен только для статей, опубликованных более двух месяцев назад.


Комментарии

Подпишитесь на ][, чтобы участвовать в обсуждении

Обсуждение этой статьи доступно только нашим подписчикам. Вы можете войти в свой аккаунт или зарегистрироваться и оплатить подписку, чтобы свободно участвовать в обсуждении.

Check Also

Безопасность превыше всего. 9 простых трюков, которые сделают жизнь линуксоида секьюрнее

Жизнь обычных людей складывается из мелочей. Жизнь линуксоида складывается из множества ма…