Соревнование Data Fusion Contest 2022 завершено. Самое время вспомнить, как это было, обсудить онлайн-трансляцию финала и подробно рассмотреть наиболее интересные и яркие решения победителей и призёров во всех категориях.

В этом году участники на практике осваивали матчинг слияние данных транзакций ВТБ – ключевого организатора соревнования, и кликстримов “Ростелекома”, угадывая одних и тех же клиентов с помощью различных инструментов DS, ML и, возможно, капельки интуиции и везения. С помощью инструментов безопасного матчинга data exchange компании Platforma и наработкам ВТБ в части алгоритмов по генерации данных был сформирован синтетический датасет на обезличенных данных от ВТБ и Ростелекома. При этом данные генерировались таким образом, чтобы сохранить необходимую для решения задачи информацию о пользовательском поведении.

Регистрация была открыта с 3 февраля до 15 мая, и уже в ночь с 16 на 17 мая нам были известны победители.

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

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

Пара слов про задачи

Задачи Matching и Puzzle шли рука об руку – вторая, по сути, могла быть использована для отладки решений первой, так что неудивительно, что 2 из 3 призовых места в категории Matching совпадают с категорией Puzzle. Давайте посмотрим, что это были за задачи, и разберем решения участников.

Matching-задача была в контейнерном формате. Что нужно было сделать конкретно – по данным транзакций и кликстрима сначала построить обезличенные вектора, а затем для каждого «клиента» ВТБ сопоставить вектора и отранжировать «клиентов» "Ростелекома" по вероятности их совпадения. Решения задачи проверялись автоматически на полностью закрытых тестовых данных в изолированной среде.

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

Решения победителей соревнований

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

3 место в Matching и 2 место в Puzzle

Решения участника для задач Matching и Puzzle схожи. Сначала на основе транзакций и кликстримов были посчитаны различные признаки. Они основывались на информации о дне и часе, mcc коде или категории, валюте и сумме (учитывалось направление транзакции), или устройстве.

Ещё в качестве признаков использовались эмбеддинги, полученные благодаря библиотеке pytorch-lifestream. Для нахождения вероятности того, что «клиент» ВТБ совпадает с «клиентом» “Ростелекома” автор решения обучал Сatboost. На каждую правильную пару случайно выбиралось 8 неправильных.

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

Чтобы посчитать ответ для задачи Puzzle, участник использовал Google Colab. На одной учетной записи он позволил одновременно делать предсказания 6-ю моделями, так как не требовался GPU.

2 место Matching и 1 в Puzzle

Решение выложено самим участником на github.

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

Сами решения следуют понятному пайплайну из трех блоков:

  1. Разнообразный feature engineering

  2. Обучение CatBoost

  3. Ансамбль нескольких моделей

1.  Feature engineering:

  • Построение признаков по времени, как в публичном решении участника, занявшее 1ое место в номинации Companion, но с существенной модификацией (дает +0.005 R1). Чтобы уменьшить шум, сначала проводим дедупликацию по дате, и только потом считаем count по юзерам и часам. То есть считаем не количество транзакций/кликов для данного юзера и часа, а количество дней, когда были транзакции/клики. И дальше естественно нормируем по юзерам, берем долю дней вместо счетчика.

  • Аналогичную процедуру проводим для основных фичей, как в публичном бейзлайне для счетчиков по юзерам и категориям. И то же самое для юзеров и кодов транзакций. Считаем количество дней, когда были клики для данного юзера и данной категории. Либо (вторая версия) считаем количество недель, когда были клики для данного юзера и категории.

  • Нормировка всех фичей по юзерам. То есть счетчик (или сумму транзакций) делим на суммарный счетчик по всем категориям для данного юзера.

  • Выбрасываем редкие категории и mcc коды. Оставляем только те, которые встречаются минимум у 50 юзеров.

Обучение:

  • Используем CatboostRanker с ранжирующим лоссом вместо обычного CatboostСlassifier. Хоть это и улучшает не так сильно, как можно было бы подумать.

  • Тренировка с большим количеством итераций. Для валидации обучал 5000 итераций, а для итоговых самбитов - 15000 итераций при lr=0.03. Чуть-чуть улучшает итоговый результат.

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

Ансамбль:

  • Простое среднее нескольких моделей (5-7 штук) с разным feature engineering и одинаковыми параметрами катбуста. На public LB ансамбль прибавил +0.005 к лучшей single модели.

Также стоит отдельно сказать, что было очень много дополнительных идей и гипотез, которые не зашли. Например:

  • Использовать фичи на основе дат (не часов).

  • Задействовать данные из puzzle для негативных примеров.

  • Как-нибудь по-умному сэмплировать негативные примеры, выбирать более похожие или наоборот непохожие - все было не лучше или хуже, чем простое сэмплирование.

  • Скрестить часы и категории в качестве фичей, то есть считать count для данного юзера, категории и часа.

  • Пробовал сделать какое-нибудь решение на нейронках, качество было очень плохим.

  • Пробовал использовать библиотеку pytorch-lifestream, учитывая, что ее авторы были на первом месте. Но с наскоку разобраться, как сделать с помощью нее end-to-end решение для этой задачи, не получилось. А тренировка эмбеддингов кликстрима и транзакций по отдельности и добавление их к CatBoost моделям не помогло.

  • LightGBM и XGBoost почему-то работали гораздо хуже, чем CatBoost, не стал с этим разбираться глубоко, просто использовал CatBoost.

1 место Matching, победитель  - команда Sberbank AI Lab

Решение, которое заняло первое место на private главной задачи, выложено самой командой на github.

 В основе решения лежит нейронная сеть. В работе активно использовали собственную открытую библиотеку для работы с последовательностями https://github.com/dllllb/pytorch-lifestream.

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

Сама сеть состоит из двух частей:

  1. TrxEncoder, переводящий каждую отдельную транзакцию в векторное представление.

  2. SequenceEncoder, сводящий последовательность векторов из TrxEncoder в один итоговый вектор.

Для обучения использовались батчи по 128 пар клиентов банка и Ростелекома. Короткие подпоследовательности транзакций семплировались дважды для каждого клиента банка и для кликстримов. Итого получалось 256 Trx последовательностей для 128 клиентов банка, и аналогично, 256 Trx последовательностей для 128 клиентов Ростелекома. Далее строили матрицу 256*256 с попарными L2-расстояниями и матрицу с метками match-unmatch. Метки использовались для семплинга (как целевого, так и негативного) и передачи в Softmax Loss.

Для pretrain-инга решение вдохновлялось идеями BERT. А именно, TrxEncoder + TransformerEncoder и MLM (Masked Language Model) задачей. TransformerEncoder использовался для предсказания масок TrxEncoder векторов.

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

Что еще пробовали, но что не зашло?

  • Некоторые фичи, например, день недели.

  • По полю new_uid считали количество, пробовали выбрасывать редкие id для каждого юзера, эмбеддить new_uid согласно частоте его встречаемости у пользователя, разделить кликстим на отдельные сессии по new_uid, обучить отдельную сетку для кластеризации new_uid. Ничего не зашло.

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

  • Трансформеры для получения окончательного эмбеддинга.

  • Смешивать транзакции и клики в одну последовательность.

  • Добавление неразмеченных последовательностей в негативные примеры.

  • Алгоритм марьяжа для корректировки output.

Решения победителей спецноминаций

Первая номинация – Insight. Это награда за самые интересные решения. Если участники используют нестандартные методы, подходы и библиотеки, и при этом достигают хороших результатов, организаторы и члены жюри просто не могут их не выделить.

Тимур Реджепов, 1 место Insight

Как получил самый высокий mrr score в задаче Puzzle (Pub LB)?

Решение по ссылке.

Тимур смешал две слабые модели, получил одну хорошую. Первая модель – наподобие бейзлайна. Во второй использовал временнЫе фичи - временнОе расстояние между транзакциями и кликстримом. Это решение давало высокий mrr, при ужасном precision. Поэтому пришлось разбавлять её с первой моделью с хорошим precision. Подробнее по ссылке выше.

Стратегические ошибки:

  1. 90% времени решал задачу Puzzle, думал сделав там хорошее решение, получится за последние пару недель перенести на основную задачу. В итоге не хватило времени реализовать идею :)

  2. Не делал кросс валидацию по второй модели, поэтому на private скатился с первого на третье место. Решение получилось time consuming, на cv нужно было около двух суток

Что сработало?

  • Вторая модель давала очень хороший буст baseline модели (50-100%).

  • Финальный prediction value можно было прогнать через min max scaler по каждому rtk и взять гармоническое среднее. Этот трюк давал всегда 5-10% к R1.

  • Данные можно было сэмплировать по месяцам, по 10 дней и тд и усреднять предикшены. Это кратно увеличивает время, дает прирост +20% к R1. Так же тут можно было нагенерить серию фичей отслеживающих динамику, типа "изменение к предыдущему периоду", попробовать не успел.

P. S.

  • Редкие mcc и cat можно было выбросить без потери в качестве, оставил по 120шт.

  • Везде использовал CatboostClassifier с logloss, iter=3500, step=0.03

И, наконец, номинация Companion – награда за лучшие публичные решения, опубликованные в ходе соревнования. Критерии просты: максимально раскрыть подходы, методы и практики в анализе данных и успеть до закрытия приема решений. Кстати, в этой номинации баллы за решения суммировались, так что участники брали не только качеством, но и количеством.

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

3 место Companion

Воспроизведено baseline решение (которое было недоступно участникам на тот момент) и инференс для задач Matching и Puzzle). В начале сделан небольшой EDA. Затем рассчитываются эмбединги по клиентам банка и ртк (счётчики по mcc-кодам и категориям кликстрима соответственно). По этим эмбедингам собирается обучающая выборка, где на 1 правильный мэтч приходится 10 неправильных (неправильные пары - случайные). Получается задача бинарной классификации, для которой обучаем CatBoostClassifier. Для инференса делаем предсказания для всех возможных пар и выбираем из них 100 с самой высокой вероятностью.

2 место в Companion

Из особенностей - использовал при обучении ранжирующий лосс - давало +15% к скору по сравнению с обычным классификатором. Плюс обрезали количество признаков до 300 самых важных по feature importance - тоже давало прирост.  Так же представлены функции удаления выбросов и локальной валидации.

Из несработавшего: генерация "умных" негативов для трэйна.

1 место Companion

В данном соревновании, как и в других, открытые решения делились на два типа:

  1. Крутые и сложные идеи, которые не помогли достичь большого скора.

  2. Идеи, которые позволили сильно улучшить метрики.

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

Церемония награждения и призеры соревнования

26 мая в офисе ВТБ прошла церемония награждения победителей соревнования, после которой они провели разбор своих решений Посмотреть как это было можно здесь.

Благодарим всех за активное участие, общение в чате, присутствие на онлайн-митапах и желание делать data science лучше!

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