Skip to content

Tikhon-Radkevich/VK-Techno-Test

Repository files navigation

Стажировка в VK
Инженер машинного обучения (Профильное задание)

Датасет intern_task.csv:

  • query_id - айдишник поисквой сессии;
  • rank - оценка релевантности;
  • фичи релевантности документа запросу.

Задача:

  • Подготовить и проверить датасет;
  • Натренировать модель, которая будет ранжировать документы по их фичам внутри одной сессии (по фичам предсказывать ранк документа);
  • посчитать метрики ранжирования для своей модели (ndcg_5 как минимум).

Содержание

Подготовка датасета

  1. Код можно найти в ноутбуке data_analysing.ipynb

    • Визуализировал распределения фичей - histograms.pdf;
    • Видно дисбаланс рангов, это нужно будет учесть во время обучения модели.
    • Проанализтровал корреляции;
    • Удалил константы и часть искуственно созданных признаков;
    • Обнаружил коллинеарность и разряженность некоторых фичей;
    • Отчищенный датасет: cleaned_data.csv

    Итого: в датасете осталось 140 колонок, что относительно много. В нём остались коллинеарность и разряженность. Анонимность фичей затрудняет их оъективную оценку, например есть 2 коллинеарных признака, однако я не знаю, какой из них оригинальный, а какой дубликат с шумом. Это затрудняет ручную отчистку датасета.

  2. Чтобы бороться с вышеупомянутыми проблемами - использую метод понижения размерности PCA. Реализация - component_analysis.ipynb

    • Оставил первые 20 компонент, они объясняют 83% дисперсии данных.
    • Новый датасет: pca_20_features.csv

Модель ранжирования

В качестве бэйзлайна использовал бустинг над деревьями, а именно CatBoostRanker из catboost.
Код обучения модели: catboost_baseline.ipynb

  • catboost предоставляет инстумент для загрузки датасета. В параметре group_id указываю колонку с сессиями, что обеспечит корректную работу модели ранжирования.
from catboost import Pool

Pool(data=X_train, label=y_train, group_id=train_data["query_id"])
  • В качестве лосса использовал YetiRank
  • Подбор оптимальных гиперпараметров осуществил с помощью библиотеки optuna
  • К сожалению YetiRank не поддерживает sample_weight, поэтому с дисбалансом классов нужно бороться как-то иначе.

Метрики

Задание предполагает использование NDCG_5. Эта метрика отлично подходит задаче ранжирования. Она учитывает как правильность знаяения предсказанного ранга, так и их порядок. Однако размеры наших сессий варьируются от 1 до 908, поэтому я решил брать гибкое число объектов для рассчёта метрики, например 20%.
Код с реализацией: tools.py

Считаю NDCG следующим образом: делаю предсказания рангов, далее соотношу предсказания с настоящими значениями, после чего сортирую документы внутри каждой сессии по рангу (предполагаю, что 4 - наиболее релевантный документ, 0 - менее релевантный) и рассчитываю метрику. Таким образом учитываю как порядок рангов, так и сами их значения.

На выходе NDCG варьируется от 0.47 до 0.74, в зависимости от количества учитываемых документов (5 и все, соответственно).
Кроме того рассчитал Spearman и Kendall корреляции: 0.37 и 0.29.

Вывод

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

TODO

  • Достаточно сильно варьируется количество документов в запросе (от 1 до 908). Можно попробовать разбить их на группы в зависимости от размера и посмотреть корреляции внутри групп.
  • Использовать другие методы отбора признаков. Я использовал PCA, однако можно попробовать методы основанные на моделях.
  • Решить проблему дисбаланса рангов. Например, использовать oversampling или рассчитать веса классов.
  • Попробовать другие модели, например LightGBM или XGBoost.