Датасет intern_task.csv:
query_id
- айдишник поисквой сессии;rank
- оценка релевантности;- фичи релевантности документа запросу.
Задача:
- Подготовить и проверить датасет;
- Натренировать модель, которая будет ранжировать документы по их фичам внутри одной сессии (по фичам предсказывать ранк документа);
- посчитать метрики ранжирования для своей модели (
ndcg_5
как минимум).
-
Код можно найти в ноутбуке data_analysing.ipynb
- Визуализировал распределения фичей - histograms.pdf;
- Видно дисбаланс рангов, это нужно будет учесть во время обучения модели.
- Проанализтровал корреляции;
- Удалил константы и часть искуственно созданных признаков;
- Обнаружил коллинеарность и разряженность некоторых фичей;
- Отчищенный датасет: cleaned_data.csv
Итого: в датасете осталось 140 колонок, что относительно много. В нём остались коллинеарность и разряженность. Анонимность фичей затрудняет их оъективную оценку, например есть 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.
Можно подвести итог: в целом модель делает какие-то предположения относительно предсказания ранга, однако есть пространство для улучшений. Могу предположить, что наибольшей проблемой в данном решении является дисбаланс предсказываемых рангов.
- Достаточно сильно варьируется количество документов в запросе (от 1 до 908). Можно попробовать разбить их на группы в зависимости от размера и посмотреть корреляции внутри групп.
- Использовать другие методы отбора признаков. Я использовал PCA, однако можно попробовать методы основанные на моделях.
- Решить проблему дисбаланса рангов. Например, использовать oversampling или рассчитать веса классов.
- Попробовать другие модели, например LightGBM или XGBoost.