Caret vs Tidymodels: как использовать оба пакета вместе?
Опубликовано: 09/01/2021 Время на прочтение: 5 минут
Фото Криса Барбалиса на Unsplash
Макс Кун создает оба пакета (при участии многих других талантливых людей). Пакет caret (сокращение от Classification And regression Training) упрощает процесс создания прогностических моделей и является лучшим выбором среди пользователей R. Он существует уже давно, и есть множество ресурсов, ответов и решений на все возможные вопросы. С другой стороны, tidymodels является более новым и построен на принципах tidyverse. RStudio наняла Макса, намереваясь разработать аккуратную версию каретки.
Я использую каретку для предсказательного моделирования. Хотя я знаю о tidymodels, я только начал исследовать их на прошлой неделе. Как и все в жизни, принятие новой экосистемы требует времени и терпения. Таким образом, этот пост ни в коем случае не является исчерпывающим анализом. Полный код доступен на GitHub,а HTML-версия Markdown опубликована.
Обзор
caret — это единый пакет с различными функциями для машинного обучения. Например, createDataPartition для разделения данных и trainControl для настройки перекрестной проверки.
tidymodels — это набор пакетов для моделирования. Когда я выполняю команду library (tidymodels), загружаются следующие пакеты:
- повторная выборка: для разделения и повторной выборки данных
- Пастернак: для опробования целого ряда моделей
- рецепты: для предварительной обработки
- рабочий процесс: для того, чтобы собрать все вместе
- критерий: для оценки моделей
- Метла: для преобразования информации в обычных статистических R-объектах в удобные для пользователя, предсказуемые форматы
- циферблаты: для создания и управления параметрами настройки
Некоторые общие библиотеки из tidyverse, такие как dplyr, также загружаются. Как показано, tidymodels разбивает рабочий процесс машинного обучения на несколько этапов и предоставляет специализированные пакеты для каждого этапа. Это выгодно для пользователей из-за повышенной гибкости и возможностей. Однако для новичка это может быть пугающим (по крайней мере, для меня).
Импорт данных
Данные взяты из набора данных Bike Sharing репозитория UCI. Цель состоит в том, чтобы предсказать общее количество проката велосипедов на основе экологических и сезонных условий.
библиотека(tidymodels)
библиотека(каретка)
библиотека(lubridate)
библиотека(tidyverse)
библиотека(моменты)
библиотека(corrr)
библиотека(randomForest)
велосипед <- read_csv("велосипед-обмен-набор данных/час.КШМ")
велосипед %>% тусклый()
## [1] 17379 17
Есть 17,379 случаи и особенности 17. Я удалил instant, изменил форматирование для year и переименовал некоторые переменные.
велосипед %>%
mutate (instant = NULL, yr = yr + 2011) %>%
переименовать(
дата = dtday,
год = год,
месяц = мес,
час = час,
погода = weathersit,
влажность = гул,
итого = УНТ
) ->
велосипедпредварительный просмотр заголовка кадра данных head (bike)
Просмотр данных
Целевая переменная
велосипед %>%
pivot_longer(
cols = c (случайный, зарегистрированный, общий),
names_to = «пользовательского»,
values_to = «граф»
) %>%
ggplot(aes(count, color = usertype)) +
geom_density () +
лаборатории(
title = » распределение количества прокатных велосипедов»,
x = «число в час», y = » плотность»
) +
scale_colour_discrete(
name = » тип пользователя»,
перерывы = c(«случайные», «зарегистрированные», » всего»),
метки = c(«незарегистрированный»,» зарегистрированный», » всего»)
)Распределение целевых переменных
Распределение арендной платы положительно искажено. Желательно иметь нормальное распределение, так как большинство методов машинного обучения требуют, чтобы зависимая переменная была нормальной. Я обратился к этой асимметрии позже.
Взаимосвязь
Я использовал функцию correlated () из пакета corrr, которая является частью tidymodels, но не загружается автоматически командой library(tidymodels). Я постоянно удивляюсь тому, как много пакетов существует в экосистеме tidy. Как правило, я отдаю приоритет аккуратным пакетам над независимыми из-за интеграции конвейера и согласованности эстетики, и corrr не является исключением.
велосипед %>%
выберите (где (is. numeric)) %>%
коррелят () %>%
перестановка (абсолютная = ложная) %>%
бритье () — >
bike_cor
Rplot (bike_cor, print_cor = TRUE)корреляционный график
Подготовка данных
Поскольку я еще не разделил данные, этот шаг не является масштабированием или центрированием данных, которые должны соответствовать учебному набору и преобразовывать тестовый набор. Здесь я сосредоточусь на процессе, который применим ко всем данным и не имеет параметра, такого как факторизация или простой математический расчет. Например, если я беру квадратный корень из числа, я могу возвести его в квадрат, чтобы узнать исходное число. Однако для нормализации мне нужно знать минимальное и максимальное значение переменной, которые могут отличаться для обучения и тестирования.
Целевая переменная
Я сосредоточился на общем подсчете, поэтому случайные и зарегистрированные переменные перемещаются. Как было предложено ранее, целевая переменная положительно искажена и требует преобразования. Я попробовал несколько распространенных методов для положительно искаженных данных и применил один с наименьшей асимметрией — кубический корень.
bike_all <- велосипед %>%
выберите (- случайный, — зарегистрированный)
# Оригинал
асимметрия (bike_all$total)
## [1] 1.277301
# Журнал
асимметрия (log10(bike_all$total))
## [1] -0.936101
# Log + константа
асимметрия (log1p(bike_all$total))
## [1] -0.8181098
# Квадратный корень
асимметрия (sqrt(bike_all$total))
## [1] 0.2864499
# Кубический корень
асимметрия (bike_all$total^(1/3))
## [1] -0.0831688
# Преобразование с кубическим корнем
bike_all$итого <- bike_all$Итого^(1 / 3)
Предикторы
Категориальные переменные преобразуются в факторы в соответствии с атрибутивной информацией, предоставляемой UCI.
сезон bike_all$<- фактор(
bike_all$сезон,
уровни = c(1, 2, 3, 4),
метки = c («весна», «лето», «осень», » зима»)
)
bike_all$праздника <- фактор(
bike_all$праздник,
уровни = c(0, 1), метки = c (FALSE, TRUE)
)
bike_all$рабочийдень <- фактор(
bike_all$рабочийдень,
уровни = c(0, 1), метки = c (FALSE, TRUE)
)
bike_all$погода <- фактор(
bike_all$погода,
уровни = c(1, 2, 3, 4),
метки = c («ясно», «облачно», «дождливо», » сильный дождь»),
ordered = TRUE
)
руководитель(bike_all)Предварительный просмотр заголовка фрейма данных
Разделение данных (поезд/тест, кросс-валидация)
Оба пакета обеспечивают функции общего разделения данных методы, такие как K-складки, сгруппированные в K раз, выйти-вышли-один, и загрузчик. Но tidyverse кажется более всеобъемлющим, поскольку он включает в себя перекрестную проверку Монте-Карло (я не знаю, что это такое, но звучит круто) и вложенную перекрестную проверку. Я особенно подчеркнул этот метод, потому что в одной исследовательской работе было обнаружено, что “вложенные подходы CV и train/test split дают надежные и непредвзятые оценки производительности независимо от размера выборки.” (Vabalas et al., 2019)
tidymodels
Библиотека rsample tidymodels обрабатывает разделение данных. Разделение обучения и тестирования выполняется, как показано на рисунке, наряду с 10-кратной перекрестной валидацией.
набор семян (25)
сплит <- initial_split(bike_all, проп = 0.8)
train_data <- тренировки(сплит)
train_data %>% Дим()
## [1] 13904 14
test_data <- тестирование(сплит)
test_data %>% Дим()
## [1] 3475 14
train_cv <- vfold_cv(train_data, в = 10)
каретка
Есть два варианта:
- Используйте собственные функции caret, такие как createDataPartition.
набор семян (25)
train_index <- createDataPartition(
bike_all$total, p = 0.8, times = 1, list = FALSE
)
train_data <- микрофоны[ train_index, ]
test_data <- микрофоны[-train_index, ]
fold_index <- createFolds(
train_data$итого,
k = 10, returnTrain = TRUE, list = TRUE
)
train_cv <- trainControl(метод="резюме", показатель = fold_index)
- Используйте функцию rsample2caret tidymodels, которая возвращает список, имитирующий элементы index и indexOut объекта trainControl.
train_cv_caret <- rsample2caret(train_cv)
ctrl_caret <- trainControl(
метод = » cv»,
индекс = индекс train_cv_caret$,
indexOut = train_cv_caret$indexOut
)
Два пакета довольно похожи. Интересно, что trainControl определяет только стратегию перекрестной проверки, но не данные. Тем не менее, благодаря командам rsample2caret() и caret2rsample() из tidymodels легко настроить повторную выборку в любом пакете, который вы предпочитаете. Здесь я использовал rsample2caret () для генерации 10-кратных индексов для caret, чтобы убедиться, что перекрестная проверка идентична для обоих.
Предварительная обработка данных
В caret один функциональный препроцесс охватывает всю предварительную обработку числовых функций, включая вменение, центрирование, масштабирование и преобразование мощности. Для категориальных функций я могу либо использовать dummyVars для создания фиктивных переменных, либо оставить его для обучения, которое обрабатывает факторы во время обучения модели. Одна вещь, которая меня расстраивает, заключается в том, что я не могу указать предварительную обработку для разных переменных. Например, я хочу использовать преобразование бокса-кокса для нормализации чрезвычайно искаженной переменной. Но препроцесс выполняет преобразование для всех предикторов. Если вы знакомы со sklearn в Python, я говорю, что мне нужен ColumnTransformer.
tidymodels
рецепты доставляют желание, позволяя мне определить рецепт или чертеж, который можно использовать для последовательного определения кодировок и предварительной обработки данных(т. е. Более того, рецепты, по-видимому, предлагают больше методов предварительной обработки. Однако, в отличие от caret, recipes не обрабатывает категориальные переменные автоматически, и мне нужно создавать фиктивные переменные вручную. Тем не менее, возможность адаптировать предварительную обработку превосходит небольшое неудобство, связанное с необходимостью генерировать фиктивные переменные.
prep_recipe <-
рецепт (всего ~ ., data = train_data) %>%
step_rm (год, месяц, день недели) %>%
step_date (дата) %>%
step_corr(all_numeric(), порог = 0.8) %>%
step_dummy(all_nominal())
каретка
Таким же образом можно использовать каре предварительной обработки (функция). Но я всегда нахожу это разочаровывающим, потому что все числовые переменные обрабатываются, и нет большой гибкости.
преп <- предварительной обработки(среза = 0.8)
Опять же, рецепт tidymodels можно использовать для каре. Здесь я использую prep() и bake () для преобразования данных, потому что caret не имеет функции рабочего процесса.
train_data_caret <-
преп(prep_recipe) %>% испечь(new_data = нуль)
test_data_caret <-
преп(prep_recipe) %>% испечь(new_data = test_data)
Модели поездов
Две пользовательские функции я буду использовать позже:
# Создание прогнозных таблиц
predict_table < - функция(модель, данные, tidy_flag) {
если (tidy_flag == правда) {
результат < - модель %>%
прогноз (данные) %>%
переименовать (pred = .pred) %>%
мутировать(
фактические = данные$итого,
pred_real = pred^3,
actual_real = Факт^3
)
} еще {
результат < - модель %>%
прогноз (данные) %>%
as_tibble_col(имя_столбца = «пред») %>%
мутировать(
фактические = данные$итого,
pred_real = pred^3,
actual_real = Факт^3
)
}
результат
}
# Извлечение RMSE для моделей
pull_rmse < - функция(result_table) {
rmse_result <- СКО(result_table, пред, фактический) %>%
тянуть(.оценка)
rmse_result_real <- СКО(result_table, pred_real, actual_real) %>%
тянуть(.оценка)
результат <- с(СКО = rmse_result, real_rmse = rmse_result_real)
}
Основание
Базовый уровень — это среднее значение общей суммы.
base_train_pred <-
тиббл(
фактический = train_data$итого,
actual_real = train_data$итого^3
) %>%
мутировать(пред = среднее(фактическое), pred_real = среднее(actual_real))base_test_pred <-
тиббл(
фактический = test_data$итого,
actual_real = test_data$total^3
) %>%
мутировать(пред = среднее(фактическое), pred_real = среднее(actual_real))base_train_rmse <- pull_rmse(base_train_pred)
печати(base_train_rmse)
## СКО real_rmse
## 2.032927 181.063306base_test_rmse <- pull_rmse(base_test_pred)
печати(base_test_rmse)
## СКО real_rmse
## 2.02608 182.61370
Деревья решений с tidymodels
Пастернак для моделирования, рабочий процесс для скважины… рабочий процесс, настройка для настройки параметров и критерий для показателей производительности. Мне также было любопытно время, поэтому я тоже записал время.
# Сложность затрат для параметра дерева решений
tree_cp <- сл(0.01, 0.1, 0.01)
набор семян (25)
tree_tidy_time1 <- Представление sys.время()
# Указать модель
tree_engine <-
decision_tree (mode = «регрессия», cost_complexity = tune ()) %>%
set_engine («rpart»)
# Набор рабочего процесса (предварительная обработка и модель)
tree_workflow <-
рабочий процесс() %>%
add_recipe (prep_recipe) %>%
add_model(tree_engine)
# Настройка параметров с помощью перекрестной проверки
tree_tune <- tune_grid(
tree_workflow,
пересчитывает = train_cv,