Последнее время пакет tidymodels активно развивается в направлении задач машинного обучения. Почему tidymodels? В R есть некоторая несогласованность между библиотеками, что является результатом разных подходов в их разработке. Несколько лет назад Макс Кун разработал пакет caret, целью которого было создать единую платформу для моделей машинного обучения, существующих в R. Caret был прекрасен во многих отношениях, но далек от идеала. Но это был прекрасный старт. В связи с этим RStudio пригласила Макса Куна для разработки “аккуратной” версии данного пакета. В итоге, мы получили tidymodels. Tidymodels, как и tidyverse, состоит из нескольких библиотек. К основным можно отнести: rsample — для разделения выборки; recipes — для предварительной обработки; parsnip — для определения модели; yardstick — для оценки модели; tune — для процедуры настройки параметров; workflows — для объединения предварительных процедур. Чтобы установить весь набор библиотек, которые содержатся в tidymodels — выполните команду: Мы будем использовать набор данных, в котором содержится информация о статусе диабета женщин племени Пима. Информация о данных: pregnant — кол-во беременностей; glucose — концентрация глюкозы в крови; pressure — артериальное давление; triceps — толщина кожной складки трицепса; insulin — 2-часовой сывороточный инсулин; mass — индекс массы тела; pedigree — функция родословной; age — возраст; diabetes — переменная класса (тест на диабет) Поверхностный анализ показывает, что в данных много нулей. Стоит отметить, что, например, индекс массы тела или толщина кожной складки трицепса не могут быть равны нулю. Это означает, что пропущенные значения в нашем наборе данных, записывались как “0”.  Построим гистограмму по triceps, чтобы убедиться в нашем предположении: Эта проблема актуальная также для параметров: glucose, pressure, insulin, mass. Давайте заменим все нули в этих данных на NA.  Для начала, разделим наш набор данных на обучающую и тестовые выборки. Обучающая выборка будет использоваться для подгонки нашей модели и настройки ее параметров, а тестовая — для оценки производительности нашей модели. Это разделение мы можем выполнить автоматически с помощью функции inital_split() (из пакета rsample), которая создает специальный объект “split”. Выводимый результат diabetes_split, сообщает нам, сколько наблюдений у нас есть в обучающем наборе, тестовом наборе и сколько в общем наблюдений: <train/test/total>. Обучающие и тестовые наборы могут быть извлечены из объекта diabetes_split с помощью функций training() и testing(). Хотя, на самом деле, мы не будем использовать эти объекты в конвейере (нам понадобится сам объект diabetes_split). В дальнейшем мы захотим выполнить некоторые настройки параметров. Для этого нам понадобится метод кросс-валидации. Для создания такого набора данных мы воспользуемся функцией vfold_cv(). "Рецепты" позволяют указать роль каждой переменной в качестве результата или предиктора, а также любые шаги предварительной обработки, которые мы хотим провести (например, нормализация, PCA и т. д.). Создание “рецепта” состоит из двух частей: Указать формулу (recipe()): необходимо указать переменную результата и переменные предиктора. Указать шаги предварительной обработки (step_zzz()): такие как: работа с пропущенными значениями, создание фиктивных переменных, масштабирование и многое другое. Например, мы можем сделать следующий “рецепт”: Иные функции пакета вы можете найти здесь. В приведённом выше примере мы использовали функции all_numeric() и all_predictors() в качестве аргументов предварительной обработки. Такие функции называются - «ролевыми селекторами» и указывают, что мы хотим применить шаг ко "всем числовым" переменным или "всем предикторным переменным". Список всех потенциальных селекторов ролей можно найти, набрав ?selections в консоли. Обратите внимание, что мы работаем с исходным объектом данных diabetes_clean, а не diabetes_train или diabetes_split. В целом, мы могли бы использовать любой из них, так как все, что "рецепт" "берет" - это имена и роли переменных результата и предиктора. Позже мы применим этот рецепт к конкретным наборам данных. Если мы распечатаем сводку по объекту diabetes_recipe, то убедимся в выше сказанном: Если вы хотите извлечь предварительно обработанный набор данных, то вы можете сначала использовать prep(), а на следующем шаге, при помощи функции juice(), извлечь  результат. На самом деле данный шаг не обязателен, так как он будет выполнен "под капотом" при подгонке модели.  Пока, мы только разделили наши данные на тестовую и обучающую выборки и указали шаги предварительной обработки данных при помощи пакета recipe. Следующее, что мы хотим сделать — нашу модель. Для этого мы воспользуемся пакетом parsnip. Parsnip предлагает унифицированный интерфейс для огромного количества моделей, существующих в R. Это значит, что мы сможем при помощи одной строки кода строить различные модели, придерживаясь одной логики.  Есть несколько основных компонентов, которые нам понадобятся для построения модели:  Тип модели: какую модель мы хотим. Для этого необходимо выбрать одну из нескольких функций, например: rand_forest() для случайного леса, logistic_reg() для логистической регрессии, svm_poly()для сингулярное разложения. С полным перечнем функций можно ознакомиться здесь. Аргументы: значения параметров модели (указывааются последовательно в разных моделях), задаем с помощью set_args(). Движок: базовый пакет, из которого должна быть получена модель (например, ranger для реализации случайного леса), задаем с помощью set_engine(). Режим: тип прогнозирования, так как различные пакеты могут выполнять как классификацию, так и регрессию. Задаем с помощью set_mode(). Например, если мы хотим подогнать модель случайного леса, реализованную пакетом ranger, для целей классификации, и хотим указать параметр mtry (количество случайно выбранных переменных, которые будут учитываться при каждом разбиении деревьев), то нам нужно задать следующую спецификацию модели: Если вы хотите в дальнейшем посмотреть на оценки важности переменных в вашей модели, необходимо будет воспользоваться аргументом importance в set_engine. Для пакета ranger важными вариантами являются impurity или permutation. В качестве другого примера воспользуемся пакетом glm для логистической регрессии: Обратите внимание, что данный код плохо подходит для конечной модели. Во-первых, как и recipe, он просто описывает модель. Во-вторых, в этой спецификации модели ничего не относится к набору данных о диабете. Кроме того, установка параметра tune() означает, что этот параметр будет настроен позже на этапе настройки конвейера (то есть, будет выбрано значение параметров, обеспечивающих наилучшую производительность). Но вы можете настроить этот параметр сами, если хотите контролировать модель, например, сделав это так: set_args(mtry = 4). Теперь мы готовы объединить модель и “рецепты” в один рабочий процесс. Это вы можете сделать при помощи workflow() из пакета workflows , куда передадите данные о модели и “рецепте”. Обратите внимание, что мы еще не реализовали этапы предварительной обработки в “рецепте” и не подогнали модель. Мы написали основу. Только после того, как мы настроим параметры или подгоним модель, мы сможем получить результаты. Поскольку у нас есть параметр mtry, нам необходимо настроить его (т. е. выбрать значение, обеспечивающее наилучшую производительность). Если у вас нет параметров для настройки, вы можете пропустить этот шаг. Обратите внимание, что для настройки мы будем использовать объект кросс-валидации diabetes_cv. Для этого мы указываем диапазон значений mtry, которые мы хотим попробовать, а затем добавляем параметр tune_grid() в наш рабочий процесс, используя пакет tune. Нас интересует два показателя: accuracy и roc_auc (пакет yardstick).  Вы можете настроить несколько параметров одновременно, использовав функцию expand.grid(). Например, expand.grid(mtry = c(3, 4, 5), trees = c(100, 500)) Всегда интересно посмотреть на результаты кросс-валидации. collect_metrics() — удобная функция, которую можно использовать для извлечения метрик, рассчитанных для объекта. И accuracy, и roc_auc, при mtry = 4 дают наилучшие результаты. Мы хотим добавить в наш рабочий процесс слой, который соответствует настроенному параметру, т.е. установить такой mtry , который дал наилучшие результаты. Если вы не настроили никаких параметров, вы можете пропустить этот шаг. Мы можем извлечь наилучшее значение для метрик точности, применив функцию select_best() к объекту tune. Затем мы можем добавить этот параметр в рабочий процесс с помощью функции finalize_workflow(). Теперь, когда мы определили наш рецепт, нашу модель и настроили параметры модели, мы готовы приступить к подгонке окончательной модели.  Поскольку вся информация содержится в объекте рабочего процесса (rf_workflow), мы применим функцию last_fit() к  rf_workflow в рамках разделенного объекта diabetes_split. Это позволит автоматически обучить модель, указанную в рабочем процессе, используя данные для обучения и произвести оценку на основе тестового набора. Обратите внимание, что создаваемый объект fit является объектом tibble со списком столбцов. Эта замечательная особенность tidymodels упрощает взаимодействие с tidyverse. Хотя для реального использования этой связи требуется умение работать с purrr. Если вы хотите избежать пакета purrr, то существуют функции, которые позволяют достаточно легко извлекать необходимую нам информацию. Так как мы используем объект diabetes_split, то метрики оцениваются только в тестовом наборе. Теперь, когда мы применим функцию collect_metrics() (напомним, что мы использовали ее при настройке параметров), она извлечет производительность конечной модели (поскольку rf_fit теперь состоит из одной конечной модели), примененной к тестовому набору. В целом производительность очень хорошая: accuracy 0.79 и AUC 0.85. Вы также можете извлечь прогнозы тестового набора с помощью функции collect_predictions(). Обратите внимание, что в объекте прогнозов — 192 строки, которые соответствуют количеству наблюдений в тестовом наборе (это некоторое доказательство того, что они основаны на тестовом наборе, а не на тренировочном). Поскольку это всего лишь обычный tibble, мы можем сгенерировать матрицу ошибок. Мы также можем построить график распределения предсказанных вероятностей для каждого класса. Вы можете использовать пакет purrr для извлечения прогнозов с помощью функции pull(). Следующий код делает почти то же самое, что и collect_predictions().  В предыдущем разделе оценивалась модель, обученная на тренировочных данных. Но как только вы определили свою окончательную модель, вы хотите обучить ее на своем полном наборе данных, а затем использовать ее для прогнозирования. Для этого вам нужно применить функцию fit() в вашем рабочем процессе. Объект final_model содержит несколько вещей, включая объект ranger, обученный с параметрами, установленными с помощью рабочего процесса, содержащегося в rf_workflow, на основе данных в diabetes_clean Если бы мы хотели предсказать статус диабета для новой женщины из племени Пима, мы бы обратились к функции predict(). Создадим пример, для новой женщины. Прогнозируемый диабетический статус для новой женщины - “отрицательный”. Если вы хотите извлечь оценки важности из своей модели, вам нужно применить функцию extract_fit_parsnip(), а затем извлечь объект fit, который содержится в выводе: Затем вы можете извлечь оценки важности при помощи объекта $variable.importance  Маркетинг и развитие бизнеса