Доброго времени суток, уважаемые читатели! Сегодня мы вновь рады приветствовать вас в увлекательном мире дата-сайентистов банка "Открытие". На связи Иван Кондраков, Константин Грушин и Станислав Арешин. Недавно мы поделились с вами нашим пайплайном разработки линейных моделей для решения задач бинарной классификации. Теперь же мы решили поведать о нашем опыте построения моделей градиентного бустинга. За последнее время команда проделала колоссальную работу: мы протестировали различные методы отбора факторов, нашли новые инсайты в данных, провели интересную (а, главное, полезную!) аналитическую работу и решили несколько Ad-hoc задач. Зовите всех к экранам, мы начинаем!

Градиентный бустинг в представлении Midjourney
Градиентный бустинг в представлении Midjourney

Постановка задачи

Итак, в первую очередь следует рассказать о самой решаемой задаче и о наших данных. Сравнение подходов было проведено на модели КИК (Кредитование на исполнение контракта). Это модель предсказания вероятности дефолтов клиентов, которым банк выдает кредит на исполнение контракта по 44-ФЗ, 223-ФЗ и 615-ПП. В случае выдачи экспресс-гарантии клиент дополнительно оценивается моделью КИК. И принимается решение о выдаче кредита на исполнение контракта, по которому была запрошена гарантия. Целевая переменная — просрочка по клиенту 90+ на горизонте 18 месяцев.

Наблюдения состоят из нескольких выборок:

  • Весь объем выданных экспресс-гарантий;

  • Набор не выданных экспресс-гарантий (отказные, а также одобренные, но не выданные);

  • Набор заключенных контрактов для транзакционных клиентов (так называемые условные заявки).

Также вкратце напомним пайплайн построения линейной модели для тех, кто все еще не ознакомился с нашей предыдущей статьей (а мы очень советуем!):

Иллюстрация пайплайна логистической регрессии
Иллюстрация пайплайна логистической регрессии

Текущая модель логистической регрессии является стекингом 6 модулей, разработанных на 6 различных подвыборках, определяемых критериями применимости модуля: Анкетный модуль, Модуль кредитной истории, Модуль контрактной истории, Модуль транзакционной истории, Модуль судебной истории, Модуль финансовой отчетности.

Перед нами стоит задача построения моделей градиентного бустинга и анализа полученных результатов, разумеется, в сравнении с существующей линейной моделью и ее модулями. Нам важно понять, насколько лучше алгоритм бустинга решает задачу ранжирования клиентов, мы оцениваем метрику Gini, смотрим на ее значение и на доверительные интервалы [0,025; 0,975].

Исходя из концепции построения логистической регрессии для адекватного сравнения мы строим следующие модели бустинга:

  • Модель на всех факторах и всех наблюдениях, сравнение которой будем проводить с моделью стекинга;

  • Одномодульные модели по каждому модулю, которые логично сопоставить с одномодульными моделями логистической регрессии.

Стоит сказать, что как базовое решение мы выбрали алгоритм CatBoost.

Обзор методов

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

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

Наш подход отбора факторов для бустинга
Наш подход отбора факторов для бустинга

Первичный отбор факторов

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

  • Удаление факторов, в которых более 95% значений — пропуски;

  • Удаление категориальных факторов с сильной грануляцией;

  • Удаление факторов по PSI train/test/val/oot или по годам.

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

Permutation importance

Данный метод, пожалуй, основной. Мы применяли его на определенном этапе при построении каждой нашей модели. Permutation importance используется для расчета важности факторов и последующего отбора в зависимости от критерия. Например:

  • Выбор топ N факторов;

  • Отбор факторов, средняя важность которых больше 0;

  • Выбор факторов, важность которых выше важности случайного фактора.

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

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

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

Prediction value change

Prediction value change показывает, насколько в среднем изменится прогноз модели при изменении значения фактора. Чем больше изменяется прогноз, тем  важнее рассматриваемый фактор. Метод чем-то похож на рассмотренный ранее Permutation importance, однако у него есть свои плюсы и минусы.

Из плюсов стоит сказать о том, что метод довольно шустрый, а для алгоритма CatBoost вообще считается по дефолту, если мы оптимизируем LogLoss.

Но есть важный недостаток, за счет которого им нельзя заменить так понравившийся нам Permutation importance: а именно, мы не можем оценить влияние на целевую метрику, так как знаем только факт, что предсказания изменились, а на вопрос, в какую сторону, данный алгоритм не отвечает.

Таким образом, Prediction value change хорошо использовать для отбора на одном из первых этапов, когда факторов слишком много для расчета пермутаций за адекватное время, а также для некоего быстрого ранжирования факторов по важности для применения других методов.

Отбор по SHAP

Значения SHAP (SHapley Additive exPlanations) используются для интерпретации результатов моделей машинного обучения. Они дают возможность объяснить результаты любой модели машинного обучения путем количественной оценки важности каждого признака в определении результатов. Идея значений SHAP заключается в том, чтобы разложить прогноз, сделанный моделью, на вклад каждого признака.

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

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

Корреляционный отбор

Для начала необходимо получить ранжированный по важности список факторов. Тут можно использовать различные подходы, например:

  • Сортировать факторы по gini фактора;

  • Строить однофакторные модели;

  • Использовать важности метода Prediction value change;

  • Использовать важности метода Permutation importance.

Мы остановились на последнем.

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

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

Модель на всех факторах

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

Ниже представлена воронка отбора факторов нашей самой большой модели:

Воронка отбора факторов модели на всех факторах
Воронка отбора факторов модели на всех факторах

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

На первом этапе проводится обор по первичным статистикам, затем Wrapper отбор по Prediction Value Change, как наиболее быстрый способ отсеять часть не влияющих на итоговые предсказания факторов.

Когда остается достаточно факторов, чтобы отбор по PSI не был долгим, мы его проводим, после чего строим бейслайн модель на 935 факторах и рассчитываем пермутации.

Далее рассматриваем разные топы факторов и оцениваем наши результаты на валидации. Основная цель данного этапа выбрать такую модель, gini которой не сильно ниже бейслайн модели (а может, и выше), но при этом количество факторов в ней заметно ниже. Это связано с модельным риском расчета слишком большого количества факторов.

Мы хотели бы продемонстрировать вам доверительные интервалы всех построенных в рамках этой подзадачи моделей, оценка проводилась бутстрепом на 500 итерациях на выборке OOT:

Доверительные интервалы всех протестированных в рамках построения модели на всех факторах моделей
Доверительные интервалы всех протестированных в рамках построения модели на всех факторах моделей

Итоговой моделью была выбрана модель "топ-250" (на графике выделена красным), как наиболее удовлетворяющая поставленным нами критериям. Gini данной модели 79,21, что довольно значительно превосходит нашу линейную стекинговую модель (выделена голубым), у которой 70,48. Плюс к этому ресурсы, затраченные на построение стекинга нескольких модулей линейной модели, несопоставимы с затратами на построение модели бустинга.

Еще при построении этой модели была решена одна очень интересная ad-hoc задачка. По воронке отбора факторов видно, что топ числовых постоянно меняется, а категориальные факторы сохраняются, то есть в топ-250 факторов их столько же, сколько и в модели на 935 факторах. Было решено построить и сравнить модели на только категориальных гранулированных, не гранулированных и числовых факторах:

Модель

Количество факторов

Gini OOT

Только гранулированные категориальные факторы

26

76,41

Только не гранулированные категориальные факторы

18

76,52

Только числовые факторы

917

76,45

Видно, что модели на категориальных факторах показывают себя так же, как и модель на числовых, а факторов в них меньше в разы. Нас этот результат очень удивил: судя по всему, наши категориальные факторы работают ну уж слишком хорошо ????. Ну и стоит отдать должное алгоритму CatBoost, не зря он Categorical и действительно хорошо показал себя на категориальных фичах.

Проблема дублей

Перед рассказом об одномодульных моделях нам важно сделать еще одно небольшое отступление. При их построении мы столкнулись с проблемой переобучения на выборке OOT. Справедливости ради скажем, что переобучение было и у модели на всех факторах, но тут оно оказалось сильнее и нам удалось выяснить причину. Дело в том, что в обучающей выборке присутствуют полные дубликаты (записи, у которых одинаковые значения всех рассматриваемых факторов), а для бустинга это приводит к увеличению весов определенных объектов. При уменьшении размерности признакового пространства количество дублированных записей растет. Этой проблемы не было в модели на всех факторах, так как там факторы разной природы, то есть более разнообразное признаковое пространство.

В подтверждение вышесказанных слов приводим результаты эксперимента:

  1. Строим модель LightGBM с подсчетом количества сплитов по фактору;

  2. Сортируем факторы по количеству сплитов;

  3. Удаляем полные дубли (KEY, N_FEATURES, TARGET) по подмножествам отсортированных в порядке количества сплитов факторов с шагом 5 штук;

  4. Удаляем полные дубли (KEY, N_FEATURES, TARGET) по подмножествам случайно отсортированных факторов с шагом 5 штук;

  5. Строим графики изменения количества наблюдений в обучающей выборке в зависимости от подмножества факторов и сравниваем результаты.

Результаты пункта 3
Результаты пункта 3
Результаты пункта 4
Результаты пункта 4

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

Модуль судебной истории

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

Воронка отбора факторов модели судебного модуля
Воронка отбора факторов модели судебного модуля

Вместо Prediction Value Change считаем важности Permutation Importance, чтобы сразу оценить влияние факторов на целевую метрику, а не на сами предсказания, благо ресурсов для такого расчета в данном модуле было достаточно. Факторы были отобраны по критерию средняя важность минус стандартное отклонение больше нуля. Далее, рассматривая топы факторов, была выбрана модель на 100 факторах по критериям, описанным ранее.

Что касается результатов, методом бутстрепа на 10000 повторениях были рассчитаны доверительные интервалы Gini линейной модели и итоговой модели бустинга для этого модуля на выборке OOT:

Доверительные интервалы модуль судебной истории
Доверительные интервалы модуль судебной истории

На графике видно, что прирост (не побоимся этого слова) огромный, а доверительные интервалы моделей не пересекаются. Если говорить о цифрах, Gini линейной модели 26,52, а у бустинга — 40,75. Кажется, пора менять модель….

Модуль финансовой отчетности

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

Давайте взглянем на нашу воронку:

Воронка отбора факторов модели финансового модуля
Воронка отбора факторов модели финансового модуля

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

Осведомленный читатель, конечно, скажет, что для бустинга не стоит удалять коррелирующие факторы, но мы выделили для себя два поинта:

  • Во-первых, удаление коррелированных факторов значимо не сказывается на метрике качества модели, при этом позволяет освободить признаковое пространство от лишних фичей. Так наша модель для финансового модуля работает лучше, то есть при 26 факторах метрика Gini выше, чем у модели со 165 факторами;

  • Во-вторых, наличие коррелированных факторов зашумляет результаты оценки важностей. Например, удалив такие факторы, гораздо проще интерпретировать результаты конкретно этого модуля библиотекой shap, мы не засоряем наш summary_plot практически одинаковыми по бизнес-смыслу факторами. Об интерпретации вкратце поговорим немного позже.

По итогу мы получили модель, Gini которой на OOT выборке 59,89, при этом у линейной модели 56,00. Прирост самый низкий из всех построенных моделей. Это наталкивает на мысль о том, что для финансового модуля, возможно, стоит оставить линейную модель, так как пространство признаков довольно простое, их ожидаемая бизнес-логика в основном линейная и как будто бы линейная модель в данном кейсе — хороший и стабильный подход.

В заключение снова приведем график доверительных интервалов на выборке OOT, результаты же надо как-то подтверждать????

Доверительные интервалы модуль финансовой отчетности
Доверительные интервалы модуль финансовой отчетности

Модуль контрактной истории

Ну и завершаем наш рассказ о моделях контрактным модулем. У контрактного модуля наиболее разнообразное признаковое пространство (топ-2 после модели на всех факторах), поэтому проблема дублей не так явно выражена. При разработке вычисления проводились на так называемой "тяжелой ноде", поэтому в ресурсах нас практически не ограничивали. Тем не менее, пайплайн этого модуля не суперзатратный по времени и его точно так же можно было бы разделить на батчи факторов.

Ключевое отличие — в применении отбора по среднему абсолютному значению SHAP на втором этапе. Данный подход работает достаточно быстро даже на 4,5 тысячах факторов благодаря великолепно оптимизированной библиотеке shap и позволяет отбросить значительное количество факторов. Главное — построить модель. Оставшиеся действия мы уже комментировали ранее.  

Воронка отбора факторов модели контрактного модуля
Воронка отбора факторов модели контрактного модуля

Итоговая модель на топ-50 факторах, прирост тоже хороший, ее Gini 45,34, а у линейной 33,33. А вот и доверительные интервалы:

Доверительные интервалы модуль контрактной истории
Доверительные интервалы модуль контрактной истории

Интерпретация

Несколько слов об интерпретации данных моделей. Для банка важно объяснить бизнесу, как факторы работают внутри модели, соответствуют ли они заложенной бизнес-логике. Мы для этого используем библиотеку shap. В среднем 90% факторов работают корректно. Однако встречаются факторы, для которых логику либо трудно определить, либо она противоположна, что очень плохо. Такие факторы стоит удалить, пусть их удаление и приводит к снижению Gini итоговых моделей. Сейчас мы разрабатываем инструмент для автоматического сопоставления бизнес логики и SHAP значений. Ведь мы же бережем время, деньги, нервы???? Кто не понял, это отсылка на нашу первую статью, которую мы также рекомендуем к прочтению!

Заключение

Настало время подводить итоги. Приведенный в качестве примера список моделей полностью описывает все разветвления нашего пайплайна. Полученные модели градиентного бустинга значительно превосходят линейные в качестве (финансовый модуль, ты не считаешься). Однако мы сталкиваемся с новыми проблемами, а именно:

  • Интерпретация влияния факторов на итоговый результат модели;

  • Модельный риск расчета большого количества факторов.

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

В заключение приводим наши планы:

  • Оценка возможности отбора факторов по соответствию заложенной бизнес-логики  и SHAP значений;

  • Оценка использования алгоритмов forward/backward selection по финальному списку факторов;

  • Оценка влияния подбора гиперпараметров на итоговый скор модели. Стекинг результатов одномодульных моделей бустинга. Здесь интересно выяснить, лучше ли она модели бустинга на всех факторах, а также дополнительно сравнить со стекингом линейных моделей.  

На этом мы заканчиваем наш рассказ, но продолжение не заставит себя ждать!)

Если у вас есть интересные практики отбора факторов для моделей градиентного бустинга, интерпретации моделей для заказчиков, просим отписаться в комментариях, нам будет интересно ознакомиться!

Комментарии (7)


  1. akhalat
    30.05.2023 18:06

    Сама важность фактора определяется как снижение оценки модели по целевой метрике на валидационной выборке при случайной перестановке значений этого фактора

    А почему просто не выбрасывать признак и сравнивать метрику с признаком/без?


    Но есть важный недостаток, за счет которого им нельзя заменить так понравившийся нам Permutation importance: а именно, мы не можем оценить влияние на целевую метрику, так как знаем только факт, что предсказания изменились, а на вопрос, в какую сторону, данный алгоритм не отвечает.

    Может я что-то не так понял, но по крайней мере из изложения следует наоборот: в случае permutation importance нельзя оценить влияние на целевую метрику (случайно перемешали, метрика изменилась, но насколько сильно изменение признака на это поменяло не понятно, т.к. изменение случайно). В случае с Prediction value change мы вроде как-то контролированно меняем значение признака и смотрим на изменение целевой метрики, т.е. можем количественно отслеживать. Хотя, тем до конца не раскрыта, как именно меняются значения признака? Просто на какое-то фиксированное значение? Меняется на фиксированную величину сразу для всех наблюдений, а потом считается по ним среднее, или что-то более хитрое?


    И, кстати, как проводится отбор по PSI?


    1. Ka_Wabanga
      30.05.2023 18:06

      Ребята все хорошо написали. Я рекомендую вам прочитать про permutation importance - очень правильный подход с стд на разных сидах.

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


      1. Koffy
        30.05.2023 18:06
        +1

        Привет!

        Спасибо за проявленный интерес к статье. Возвращаемся с комментариями.


        Permutation Importance: Согласны с тем, что не совсем правильно просто выбросить признак и сравнить до/после по целевой метрике. Во-первых потому что нужно будет перестраивать модель (так как это метод wrapper и его реализация привязана к построенной модели), а это вычислительно сложно. И поддерживаем, что выкидывая признак, мы можем потерять очень важные взаимосвязи между выброшенным и оставшимися факторами. В нашем случае мы используем данный алгоритм, чтобы выкинуть заведомо очень плохие факторы.


        PredictionValueChange: Изменение предсказания не равно изменению целевой метрики в строгом смысле. То есть признак может быть важен и предсказания чувствительны к его изменению, но на целевой метрике значимым образом это может и не отразиться. В этом методе мы целевую метрику не считаем. О подробностях расчета PredictionValueChange рекомендуем обратиться к документации CatBoost - мы использовали его нативную реализацию.


        Отбор по PSI: У нас есть разные стратегии отбора. Например, мы можем сравнивать период t против периода t+1 (последовательным образом); либо каждый период сравниваем с каждым. Эти расчеты выполняем на уровне каждого фактора и каждого типа периода (год, месяц и т.п. в зависимости от задачи). Затем каким-либо образом аггрегируем результаты по периоду и между периодами. Это может быть какой-то прокси-скор, который зависит от свежести рассматриваемого периода, важности того или иного типа периода, а может быть просто максимальное значение метрики по всем срезам.


        1. akhalat
          30.05.2023 18:06

          Во-первых потому что нужно будет перестраивать модель

          Это действительно может быть важно. Но почему тогда просто не занулять или заполнить ещё каким-то константым значением (и это быстрее случайной перестановки)?
          Насчет взаимосвязи с другими признаками: так разве мы всё равно эту взаимосвязь точно также не рушим, переставляя значения признака случайным образом? Какие вообще типы взаимосвязей могут сохраниться при случайной перестановке?


          Ну и, наконец, итоговая цель же всего действа — отбор фичей. Допустим, признак оказался незначительным в ходе permutation importance, итоговая модель будет построена без него, т.е. он в любом случае будет отброшен.


          Затем каким-либо образом аггрегируем результаты по периоду и между периодами. Это может быть какой-то прокси-скор, который зависит от свежести рассматриваемого периода, важности того или иного типа периода, а может быть просто максимальное значение метрики по всем срезам.

          Т.е. сам PSI индекс не используется, просто название выбрано в силу схожести по смыслу?


  1. CrazyElf
    30.05.2023 18:06

    Очень хорошо написано, приятно читать. ) Но по ходу возник вопрос - вот эти top100, top50, top25 выбраны фиксировано, или пробовали и промежуточные варианты, просто оставили только эти для презентации? Вдруг там внезапно скачок метрики на top42, например, а вы его пропустили из-за такого подхода? )


    1. Koffy
      30.05.2023 18:06

      Спасибо! Мы рады, что статья понравилась!

      В рамках этой задачки и конкретной ее итерации мы смотрели только на фиксированные топы факторов. Замечание дано по делу и позволит сэкономить на признаковом пространстве, при сохранении приемлемого уровня качества модели, хоть и потребует вычисления n-моделей. Один из способов, который мы не применили тут, но который нам нравится на финальном шаге - это разные реализации последовательного включения/исключения факторов (по итогам их сортировки от лучших к худшим по тем же Permutatuion Importance например) и оценка изменения качества с каким-либо критерием останова. Мы опробовали такие подходы в некоторых задачах, что позволило нам сократить признаковое пространство с сохранением/улучшением скора.


      1. CrazyElf
        30.05.2023 18:06

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