В этом посте будет рассказано о создании модели с помощью mlr3. Он будет охватывать:

  • Настройка — как установить mlr3 и загрузить в свой набор данных.
  • Познакомьтесь со своими данными. Что важно знать о наборе данных, с которым вы работаете, и как это может повлиять на ваш выбор алгоритма машинного обучения?
  • Настройка учащегося — что такое учащийся и как его настроить?
  • Важные примечания к моделям обучения. Как лучше всего начать обучение модели и почему?
  • Использование повторной выборки для обучения модели — Как использовать передискретизацию в mlr3. Как измерить производительность обученной модели.
  • Демонстрации — почему обучение и тестирование на одних и тех же данных неразумно и почему простое разделение обучения и тестирования — не лучшее решение.

Настраивать

Первым шагом при использовании mlr3 является установка и загрузка библиотеки. Вам нужно установить его только один раз. Загрузка библиотеки должна выполняться каждый раз.

# install.packages("mlr3")
library("mlr3")
# setting a seed will ensure your output matches the post output
set.seed(3)

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



task = tsk("penguins")

Если вы загружаете набор данных из data.frame, для загрузки можно использовать следующие функции:

  • as_task_classif(x, target) —для задач классификации, где x — это data.frame, а target — имя. столбца, который вы хотите предсказать.
  • as_task_regr(x, target) —для задач регрессии, где x — это data.frame, а target — это имя столбца, который вы хотите предсказать.
  • as_task_unsupervised(x) —для неконтролируемых задач, где x – это кадр данных.

Ознакомьтесь с данными

Прежде чем начать, важно отметить несколько вещей, касающихся данных:

  1. Тип ответа/цели — это важно, потому что объекты измерения задачи, учащегося и производительности в mlr3 зависят от типа ответа. Если ответ имеет тип fct, это будет задача классификации (TaskClassif), а если это int или dbl (числовой) это будет задача регрессии (TaskRegr).
  2. Типы функций — это важно, потому что некоторые учащиеся не поддерживают все типы функций. Например, classif.svm (машина опорных векторов классификации) не поддерживает категориальные функции. Это можно решить с помощью кодирования этих функций.
  3. Пропущенные значения — аналогично № 2, некоторые учащиеся не поддерживают пропущенные значения. Это можно решить с помощью вменения.
task
# <TaskClassif:penguins> (344 x 8): Palmer Penguins
# * Target: species
# * Properties: multiclass
# * Features (7):
#   - int (3): body_mass, flipper_length, year
#   - dbl (2): bill_depth, bill_length
#   - fct (2): island, sex

Распечатав эту задачу, мы можем увидеть типы функций. Набор данных «пингвины» имеет цель категориального (fct) типа (что делает это проблемой классификации), 3 объекта целочисленного (int) типа, 2 объекта двойного (dbl ) и 2 категориальных (fct) характеристик типа.

Чтобы узнать, есть ли в задаче пропущенные значения, можно использовать поле $missings(). Для целей этого поста мы не будем беспокоиться об отсутствующих значениях, однако для решения этой проблемы можно использовать вменение.

task$missings()
#        species     bill_depth    bill_length      body_mass flipper_length 
#              0              2              2              2              2 
#         island            sex           year 
#              0             11              0

Настройка учащегося

Учащиеся — это объект mlr3, который инкапсулирует многие популярные алгоритмы машинного обучения. У каждого учащегося есть функции $train() и $predict(), которые позволяют пользователям легко использовать эти алгоритмы. В этом посте рассказывается о рекомендуемом способе обучения и тестирования модели в разделе повторной выборки. Вы захотите выбрать из доступных учеников, которые специализируются на интересующем вас типе задачи. Например, задача «пингвины» — это задача классификации, поэтому я выберу из доступных учеников классификации (ученики, имена которых начинаются с «классифицировать».):



В этом примере мы будем использовать дерево классификации (classif.rpart). Учащихся можно легко инициализировать с помощью сахарной функции lrn().

learner = lrn("classif.rpart")

Теперь мы определили задачу (проблема классификации пингвинов) и ученика (дерево классификации). Мы готовы обучить ученика этой задаче.

Важные примечания к моделям обучения

У вас может возникнуть соблазн обучить учащегося на данных прямо сейчас, однако важно подумать, как мы будем измерять производительность нашей модели. Мы хотим определить «оценку производительности обобщения» модели, которую мы создаем, потому что это значение будет сообщать, как мы ожидаем работать от модели с новыми данными. При обучении модели мы хотим имитировать это, наблюдая, как обученная модель работает с данными, которые она не использовала для обучения (отдельные обучающие и тестовые наборы).

Возможно, что при разбиении данных на эти наборы вы можете получить «удачное» (положительно работает на тестовых данных) разделение один раз и «неудачное» (плохо работает на тестовых данных) разделение в следующий раз на тех же данных. . Это проблема, потому что какая оценка производительности является более точной? Мы не знаем.

В конце этого поста две демонстрации, которые иллюстрируют, во-первых, почему обучение модели на всех доступных данных — плохая идея, а во-вторых, почему обучать и тестировать только наборы (хотя и лучше) — не лучшая практика.

Оказывается, хороший способ получить обобщенную оценку производительности — многократно разделить данные на обучающие и тестовые наборы, а затем агрегировать производительность. Это называется повторной выборкой.

Использование повторной выборки для обучения модели

Перекрестная проверка — это метод, который мы будем использовать в этом примере. Для инициализации объекта передискретизации мы используем сахарную функцию rsmp(). Определяем тип ресемплинга и количество кратностей.

cv = rsmp("cv", folds=10)

Другие типы повторной выборки, реализованные в mlr3, можно найти здесь:



Мы установим для store_models значение TRUE, чтобы мы могли просмотреть отдельные модели позже (по умолчанию это значение FALSE, чтобы ограничить потребление памяти).

rr = resample(task, learner, cv, store_models = TRUE)
# INFO  [14:56:20.817] [mlr3] Applying learner 'classif.rpart' on task 'penguins' (iter 1/10)
# INFO  [14:56:21.031] [mlr3] Applying learner 'classif.rpart' on task 'penguins' (iter 2/10)
# INFO  [14:56:21.057] [mlr3] Applying learner 'classif.rpart' on task 'penguins' (iter 3/10)
# INFO  [14:56:21.081] [mlr3] Applying learner 'classif.rpart' on task 'penguins' (iter 4/10)
# INFO  [14:56:21.102] [mlr3] Applying learner 'classif.rpart' on task 'penguins' (iter 5/10)
# INFO  [14:56:21.121] [mlr3] Applying learner 'classif.rpart' on task 'penguins' (iter 6/10)
# INFO  [14:56:21.140] [mlr3] Applying learner 'classif.rpart' on task 'penguins' (iter 7/10)
# INFO  [14:56:21.160] [mlr3] Applying learner 'classif.rpart' on task 'penguins' (iter 8/10)
# INFO  [14:56:21.179] [mlr3] Applying learner 'classif.rpart' on task 'penguins' (iter 9/10)
# INFO  [14:56:21.197] [mlr3] Applying learner 'classif.rpart' on task 'penguins' (iter 10/10)

Визуализация модели

Мы можем визуализировать предсказания отдельных складок с помощью autoplot():

#install.packages("mlr3viz")
library("mlr3viz")

autoplot(rr$predictions(predict_sets = "test")[[1]])

Производительность модели

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

rr$predictions(predict_sets = "test")[[1]]$confusion
#            truth
# response    Adelie Chinstrap Gentoo
#   Adelie        13         1      0
#   Chinstrap      0         6      0
#   Gentoo         0         2     13

Хотя матрица путаницы показывает производительность модели в целом, мы можем количественно оценить прогностическую эффективность нашей модели, вызвав $score(). Существует несколько различных методов оценки (показателей) на выбор, показатели, применимые к этой задаче, начинаются с «classif.». Полный список смотрите здесь:



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

measure = msr("classif.ce")
rr$aggregate(measure)
# classif.ce 
# 0.05512605

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

Демо

Демонстрация обучающих данных

Эта демонстрация показывает опасность обучения и тестирования на одном и том же наборе данных. Давайте обучим модель на всех доступных данных (опустив несколько строк для демонстрационных целей).

# Training
learner$train(task, row_ids = 1:300)

# Prediction (on the same data)
prediction = learner$predict(task, row_ids = 1:300)

# Evaluation (using classification error)
prediction$score(measure)
# classif.ce 
# 0.02666667

Это означает, что созданная нами модель предсказала неправильный класс только в 2,67% случаев. Теперь, если вы планируете использовать эту модель, вы можете сообщить, что модель имеет ошибку классификации 2,67%, и запустить модель в производство. Теперь давайте представим, что вы развернули эту модель и получили набор новых данных, и вы хотите использовать созданную вами модель.

new_predictions = learner$predict(task, row_ids = 300:344)
new_predictions$score(measure)
# classif.ce 
#  0.2222222

Можно было бы ожидать, что ошибка классификации будет около 0,0267 на основе ошибки в обучающем наборе. Сюрприз! Это не так, реальная ошибка классификации 0,2222, что составляет 22,22%! Это почти в 10 раз хуже, чем мы ожидали.

Обучайте и тестируйте сплит-демонстрацию

Использование разделения обучения и тестирования может привести к более точным оценкам производительности. Однако это не идеальный метод. В этом разделе будет показано, почему разделение обучения и тестирования может иногда приводить к вводящим в заблуждение оценкам производительности из-за «удачного» и «неудачного» разделения. Следующие два фрагмента кода показывают две модели, обучающиеся совершенно одинаково с разными случайными начальными значениями. Обратите внимание, насколько отличается производительность.

# model 1
set.seed(3)
splits = partition(task, ratio = 0.8, cat_col="species")
learner$train(task, splits$train)
prediction = learner$predict(task, splits$test)
prediction$score(measure)
# classif.ce 
#  0.1014493
# model 2
set.seed(22)
splits = partition(task, ratio = 0.8, cat_col="species")
learner$train(task, splits$train)
prediction = learner$predict(task, splits$test)
prediction$score(measure)
# classif.ce 
# 0.01449275

Это огромная разница в ошибке классификации. В первой модели примерно 10% набора тестов было неправильно классифицировано, а во второй модели неправильно классифицировано только ~ 1,5% набора тестов. Теперь мы понятия не имеем, какой результат является более точным представлением эффективности обобщения моделей в этой задаче. Решение этой проблемы - ресемплинг!