![](https://habrastorage.org/getpro/habr/upload_files/a62/e3a/f34/a62e3af34c9429249f11132bf82a20c5.jpg)
Соревнование Data Fusion Contest 2022 завершено. Самое время вспомнить, как это было, обсудить онлайн-трансляцию финала и подробно рассмотреть наиболее интересные и яркие решения победителей и призёров во всех категориях.
В этом году участники на практике осваивали матчинг слияние данных транзакций ВТБ – ключевого организатора соревнования, и кликстримов “Ростелекома”, угадывая одних и тех же клиентов с помощью различных инструментов DS, ML и, возможно, капельки интуиции и везения. С помощью инструментов безопасного матчинга data exchange компании Platforma и наработкам ВТБ в части алгоритмов по генерации данных был сформирован синтетический датасет на обезличенных данных от ВТБ и Ростелекома. При этом данные генерировались таким образом, чтобы сохранить необходимую для решения задачи информацию о пользовательском поведении.
Регистрация была открыта с 3 февраля до 15 мая, и уже в ночь с 16 на 17 мая нам были известны победители.
Для участников были проведены тематические воркшопы и митапы. Такие встречи полезны не только для общего развития и будущих проектов, но и для решения конкретных задач прямо здесь и сейчас. Например, на одном из митапов авторы задачи Matching рассказали про основные подходы к решению, разобрали бейзлайн и даже подкинули пару предложений для его улучшения, а на другой встрече участники обсуждали публичные решения и делились своими идеями.
Подобные мероприятия повысили шансы участников не только на победу, но и на получение памятного мерча, ведь в нашем соревновании призы давались как за места на лидерборде, так и за активность.
Пара слов про задачи
Задачи Matching и Puzzle шли рука об руку – вторая, по сути, могла быть использована для отладки решений первой, так что неудивительно, что 2 из 3 призовых места в категории Matching совпадают с категорией Puzzle. Давайте посмотрим, что это были за задачи, и разберем решения участников.
Matching-задача была в контейнерном формате. Что нужно было сделать конкретно – по данным транзакций и кликстрима сначала построить обезличенные вектора, а затем для каждого «клиента» ВТБ сопоставить вектора и отранжировать «клиентов» "Ростелекома" по вероятности их совпадения. Решения задачи проверялись автоматически на полностью закрытых тестовых данных в изолированной среде.
Puzzle же имеет классический табличный вариант проверки. В этой задаче все кандидаты были известны, но сами пары не были предоставлены. Из-за схожести пост-обработки с составлением пазла она и получила своё говорящее название.
![](https://habrastorage.org/getpro/habr/upload_files/fca/d2f/5e0/fcad2f5e0a6d2625e2111ac60fb24e28.jpg)
Решения победителей соревнований
Подходы, начинка, секретный соус, грабли и эксперименты, приведшие участников к победе. Описания решений составлены со слов самих победителей:
3 место в Matching и 2 место в Puzzle
Решения участника для задач Matching и Puzzle схожи. Сначала на основе транзакций и кликстримов были посчитаны различные признаки. Они основывались на информации о дне и часе, mcc коде или категории, валюте и сумме (учитывалось направление транзакции), или устройстве.
Ещё в качестве признаков использовались эмбеддинги, полученные благодаря библиотеке pytorch-lifestream. Для нахождения вероятности того, что «клиент» ВТБ совпадает с «клиентом» “Ростелекома” автор решения обучал Сatboost. На каждую правильную пару случайно выбиралось 8 неправильных.
Чтобы сделать решение более стабильным и повысить качество он, немного меняя параметры, обучил множество моделей на разных наборах данных. Предсказанные моделями вероятности суммировались и усреднялись.
Чтобы посчитать ответ для задачи Puzzle, участник использовал Google Colab. На одной учетной записи он позволил одновременно делать предсказания 6-ю моделями, так как не требовался GPU.
2 место Matching и 1 в Puzzle
Решение выложено самим участником на github.
Решения автора для обеих задач практически идентичны. Отличие в основном в том, что для задачи Puzzle добавлены еще пару моделей в ансамбль, хотя со слов автора решений, это не сильно повлияло на итоговый результат.
Сами решения следуют понятному пайплайну из трех блоков:
Разнообразный feature engineering
Обучение CatBoost
Ансамбль нескольких моделей
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-расстояний между эмбеддингами последовательности транзакций и последовательности кликстримов.
Сама сеть состоит из двух частей:
TrxEncoder, переводящий каждую отдельную транзакцию в векторное представление.
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. Подробнее по ссылке выше.
Стратегические ошибки:
90% времени решал задачу Puzzle, думал сделав там хорошее решение, получится за последние пару недель перенести на основную задачу. В итоге не хватило времени реализовать идею :)
Не делал кросс валидацию по второй модели, поэтому на 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
В данном соревновании, как и в других, открытые решения делились на два типа:
Крутые и сложные идеи, которые не помогли достичь большого скора.
Идеи, которые позволили сильно улучшить метрики.
Открытое решение участника относилось ко второму типу. Взяли решение из безлайна, к нему добавили эмбединги по часам произведенных транзакций и кликстримов, обучив CatBoost на дефолтных параметрах.Такой подход позволил за две недели до конца соревнований оказаться в топ-10.
Церемония награждения и призеры соревнования
26 мая в офисе ВТБ прошла церемония награждения победителей соревнования, после которой они провели разбор своих решений Посмотреть как это было можно здесь.
![](https://habrastorage.org/getpro/habr/upload_files/219/b7b/b9d/219b7bb9d1500da203b3f02b35a96b06.png)
Благодарим всех за активное участие, общение в чате, присутствие на онлайн-митапах и желание делать data science лучше!