Привет, Хабр!
Это одна из трех статей, в которых я (автор канала Зайцем по ХаХатонам) рассказываю о задачах Всеросийского чемпионата Цифрового Прорыва, объясняю базовые решения (baseline) и даю советы, которые помогут подняться выше по рейтингу. В данной статье будет рассмотрен кейс от РБК по предсказанию численных характеристик, которые в полной мере показывают популярность статьи.
Спойлер: в конце статьи есть советы для улучшения базового решения.
Цифровой Прорыв
Думаю, все и так знают, что такое Цифровой Прорыв. Однако, напомню, что в этом году основной тематикой стал искусственный интеллект. И сезон этого года в самом разгаре!
Хоть часть мероприятий уже прошла, впереди участников ждет ещё 19 региональных чемпионатов, 5 окружных хакатонов и 3 всероссийских чемпионата. Советую присоединиться ко мне и другим участникам, чтобы не упустить возможность выиграть денежные призы и крутые путешествия, а также набраться опыта на самых разных задачах.
Введение
Фраза “в нужный момент в нужном месте” хорошо описывает положение авторских текстов. Иногда качественно написанная статья проходит мимо своей потенциальной аудитории из-за более актуальных тем дня или неудачного заголовка.
Хорошо, что алгоритмы ИИ активно продвинулись в анализе текста и способны в автоматическом режиме анализировать и вычленять тенденции, а имея большой набор данных, можно научиться предсказывать их наперед.
Разумеется, что есть такие общемировые темы, которые невозможно предсказать, как, например, пандемия “коронавируса” или застрявший контейнеровоз, тем не менее исследования специалистов показывают, что в обществе есть тенденции, которые приходят и уходят в фиксированный временной период.
Условие задачи
У компании РБК довольно взрослая аудитория, которую она хочет расширить за счет добавления статей на актуальные темы. Для этого вам нужно проанализировать лучшие новости российских СМИ и научиться предсказывать их популярность. Ожидается, что для этого будут использованы NLP модели.
Данные
train.csv — файл для обучения, содержит 7000 строчек, каждая из которых представляет из себя одну новостную статью
test.csv — файл, содержащий 3000 строк, для предсказания
-
sample_solution.csv — пример файла для отправки
В наборе данных присутствует уникальных 11 строк:
document id - идентификатор
title - заголовок статьи
publish_date - время публикации
session - номер сессии
authors - код автора
views - количество просмотров
depth - объем прочитанного материала
full_reads percent - процент читателей полностью прочитавших статью
ctr - показатель кликабельности
category - категория статьи
tags - ключевые слова в статье
Метрика
Цель модели участников — предсказать 3 численные характеристики, которые в полной мере показывают популярность статьи: views, full reads percent, depth.
Для оценки качества решения используется метрика R2.
???????????????????????? = 0. 4 * ????2???????????????????? + 0. 3 * ????2???????????????? ???????????????????? ???????????????????????????? + 0. 3 * ????2????????????????h
Подробно о решении
Методология решения
Решение данной задачи включает в себя два этапа:
Подготовка и предобработка данных
Обучение регрессионной модели
Какие библиотеки нам нужны
Для данного решение нам понадобится всего две библиотеки pandas и sklearn. Соответственно, импортируем их и нужные нам функции
import pandas as pd
from sklearn.metrics import r2_score
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor
from sklearn.datasets import make_regression
Загрузка данных
Далее загрузим тренировочный и тестовый наборы данных. И выведем информацию о датасете.
df_train = pd.read_csv("/content/train.csv", index_col= 0)
df_test = pd.read_csv("/content/test.csv", index_col= 0)
df_train.info()
В информации о датасете можно заметить наличие временных и категориальных признаков, которые нельзя подать в модель напрямую.
Data columns (total 10 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 title 7000 non-null object
1 publish_date 7000 non-null object
2 session 7000 non-null object
3 authors 7000 non-null int64
4 ctr 7000 non-null float64
5 category 7000 non-null int64
6 tags 7000 non-null object
7 views 7000 non-null int64
8 depth 7000 non-null float64
9 full_reads_percent 7000 non-null float64
dtypes: float64(3), int64(3), object(4)
Преобразования данных
В следующем шаге мы закодируем категорию статьи и автора в численное представление. Из временного признака - даты публикации, необходимо извлечь информацию о дне и месяце.
df_train["category"] = df_train["category"].astype('category')
df_train["category"] = df_train["category"].cat.codes
df_train["category"] = df_train["category"].astype('int')
df_train["authors"] = df_train["authors"].astype('category')
df_train["authors"] = df_train["authors"].cat.codes
df_train["authors"] = df_train["authors"].astype('int')
df_train['day'] = pd.to_datetime(df_train['publish_date']).dt.strftime("%d").astype(int)
df_train['month'] = pd.to_datetime(df_train['publish_date']).dt.strftime("%m").astype(int)
df_train.head(3)
Проделаем те же самые операции с тестовым набором данных.
df_test["category"] = df_test["category"].astype('category')
df_test["category"] = df_test["category"].cat.codes
df_test["category"] = df_test["category"].astype('int')
df_test["authors"] = df_test["authors"].astype('category')
df_test["authors"] = df_test["authors"].cat.codes
df_test["authors"] = df_test["authors"].astype('int')
df_test['day'] = pd.to_datetime(df_test['publish_date']).dt.strftime("%d").astype(int)
df_test['month'] = pd.to_datetime(df_test['publish_date']).dt.strftime("%m").astype(int)
df_test.head(3)
Визуализация данных
Для лучшего понимания данных стоит взглянуть на распределение отдельных признаков.
features = list(set(df_train.columns) - set(['publish_date']))
_ = df_train[features].hist(figsize=(20,12))
Подготовка данных для обучения модели
Для начала разделим датасет по столбцам, в X пойдут столбцы с признаками, в y таргетные столбцы.
X = df_train.drop(["views","depth","full_reads_percent","title","publish_date", "session", "tags"], axis = 1)
y = df_train[["views","depth","full_reads_percent"]]
X.head()
Следующим шагом будет разделение X и y на тренировочную и валидационную части при помощи функции train_test_split из библиотеки sklearn.
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
Обучение и тестирование модели
Перейдем к долгожданному этапу обучения модели. Для базового решения будет использован RandomForestRegressor из sklearn.
regr = RandomForestRegressor(random_state=0)
regr.fit(X_train, y_train)
Создадим предсказания на валидационных данных и посчитаем метрику.
pred = regr.predict(X_test)
score_views = r2_score(y_test["views"], pred[:,0])
score_depth = r2_score(y_test["depth"], pred[:,1])
score_frp = r2_score(y_test["full_reads_percent"], pred[:,2])
Формулу для метрики можно найти выше. На валидации получаем скор равный 0.549725, что уже неплохо.
score = 0.4 * score_views + 0.3 * score_depth + 0.3 * score_frp
score
0.5497252178188364
Создание предсказаний на тестовых данных
Для отправки решения на платформу нам нужно создать предсказания на тестовых данных и сохранить в csv-формат.
pred = regr.predict(df_test[X.columns])
df_test["views"] = pred[:,0]
df_test["depth"] = pred[:,1]
df_test["full_reads_percent"] = pred[:,2]
df_test.reset_index()[['document_id', 'views', 'depth', 'full_reads_percent']] \
.to_csv('base_solution.csv', index=False)
При отправке данного решения на лидерборде увидим скор 0.485415. Лучший же результат на момент написания статьи равен 0.788117. Однако, не стоит отчаиваться, ведь есть огромное количество возможностей по улучшению решения.
Рекомендации для улучшения результата
Как улучшить данные
В чате чемпионата уже не один раз участники отмечали важность данных, которые можно спарсить из открытых источников. Так что советую посмотреть, что полезного можно извлечь с сайта РБК.
Мы никак не использовали такие признаки, как title и tags, которые потенциально несут в себе крайне полезную информацию. Тем более, что даже авторы задачи ставили её как NLP-задачу, а значит признак title крайне важен. С тем, что получится спарсить также нужно будет провести тщательную работу по генерации полезных признаков.
Варианты улучшения модели
В базовом решение используется самая простая модель. Сразу на ум приходит замена данной модели на градиентный бустинг, например, Catboost.
Построение ансамблей из нескольких моделей, как и в других соревнованиях, могут помочь в улучшении скора.
Также стоит задуматься об использовании языковых моделей (NLP).
Итоги
Данная задача в какой-то степени является мультимодальной, так как включает в себя и табличные и текстовые данные, чем становится интересной для решения. К тому же есть множество вариантов расширения набора данных другими интересными фичами.
Все интересующие вас вопросе вы можете задать в канале Зайцем по ХаХатонам.
Всем удачи на хакатонах и чемпионатах!
sergeyns
Да ладно, что так сложно? Побольше чернухи-порнухи, и популярность обеспечена. Даже на рбк. *сарказм*
sweetlhare Автор
Вполне адекватная задача на мой взгляд.