Регрессия, персонализация и синдром Кагл

Регрессия, персонализация и синдром Кагл три ключевых аспекта в мире красоты и моды

Фото Артем Беляйкин на Unsplash

Недавно я работала над исследовательскими данными предсказания с помощью набора данных Kaggle Black Friday Prediction, который был создан шесть лет назад и был загружен более 32 000 раз. В то время как на Kaggle доступно более 100 общедоступных записных книжек по этому набору данных, а еще больше доступно в других местах, я обнаружила, что большинство из этих решений плохо реализованы.

Не помогает просто указывать на недостатки в работе других людей. Однако, когда многие люди делают одни и те же ошибки, стоит исследовать скрытые закономерности. В этом посте я расскажу о распространенных проблемах с существующими решениями, объясню, почему я больше не являюсь поклонником Kaggle, предложу лучшее решение и описываю индивидуализированный подход к предсказаниям.

Повестка дня

· EDA· Пропуск цели· Синдром Kaggle· Регрессия That Works· Индивидуализация· Прощальные слова· Ссылки

EDA (Initial Data Analysis)

Хотя набор данных Kaggle Black Friday Prediction популярен, его цель не ясна, и нет словаря данных, объясняющего данные подробно. Прежде чем мы сможем провести дальнейший анализ, нам нужно понять цель набора данных, как он был подготовлен и почему он был разработан определенным образом. Эта информация необходима для создания характеристик, выбора модели и оценки в будущем. В реальных проектах машинного обучения этот предварительный анализ также важен, потому что лучшие решения машинного обучения могут быть созданы только на основе глубокого понимания данных.

Давайте пропустим анализ данных. Выглядят они следующим образом:

Набор данных содержит 537577 строк и 12 столбцов, разделенных на группы характеристик профиля пользователя и характеристик продукта, описанных ниже:

Группа характеристик пользователя:

  • User_ID: Уникальный идентификатор пользователя. Всего в наборе данных 5891 пользователь.
  • Gender: указывает пол человека, осуществляющего транзакцию, в формате М/Ж.
  • Age: указывает возрастную группу человека, осуществляющего транзакцию.
  • Occupation: показывает профессию пользователя, обозначенную числами от 0 до 20.
  • City_Category: Категория города проживания пользователя, города категоризированы по трем различным категориям: ‘A’, ‘B’, и ‘C’.
  • Stay_In_Current_City_Years: указывает, как долго пользователь живет в этом городе.
  • Marital_Status: равно 0, если пользователь не женат или замужем, и 1 в противном случае.

Группа характеристик продукта:

  • Product_ID: Уникальный идентификатор продукта. Всего в наборе данных 3623 продукта.
  • Product_Category_1 to _3: Категория продукта. Все три обозначены числами.

Целевой признак:

  • Purchase: Сумма покупки.

Как показано в профиле набора данных, присутствуют как целые числа, так и категориальные признаки. 31,6% значений Product_Category_2 отсутствуют, в то время как отсутствует 69,7% значений Product_Category_3.

В данных есть несколько интересных деталей. Например, Product_Category_1 всегда больше, чем Product_Category_2, и Product_Category_2 всегда больше, чем Product_Category_3. Это означает логическую связь между этими тремя характеристиками, однако это не было объяснено. Возможно, эти три категории связаны со временными рамками. Например, время доставки vs. время хранения vs. время, когда товар снят с продажи и т. д. Однако это только догадка. Мы не можем полностью использовать этот шаблон.

Поскольку цель набора данных не описана, давайте наденем свои шляпы детектива и спросим: “Где разработчик набора данных скрывает свои истинные намерения?” Ответ находится в контрольной выборке. В конце концов, выборка для теста – это то, как разработчик оценивает производительность модели. Поэтому давайте сравним тренировочный и тестовый наборы данных и посмотрим, что мы можем найти.

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

Упущенная цель

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

Чтобы модель училась на персонализированных взаимодействиях, как пользовательские, так и продуктовые признаки должны рассматриваться как категориальные признаки. В большинстве случаев оба из них имеют большое количество уровней. В нашем случае предсказания для Black Friday включают 5891 пользователей и 3623 продукта. Это уже очень маленький набор данных, но он уже выходит за зону комфорта для обычных регрессионных моделей.

Стандартным методом для регрессионных моделей работы с категориальными признаками является one-hot encoding, то есть каждый категориальный уровень становится новым столбцом. Однако этот подход не подходит для задачи персонализации, поскольку 5891 x 3623 приведет к получению очень большого и очень разреженного 2D-массива. Количество ячеек в массиве гораздо больше количества строк в наборе данных. Результирующий массив настолько разреженный, что большинство ячеек будут пустыми. Это затрудняет вычисления, и, что более важно, обычные регрессионные модели не смогут извлечь из массива никакой информации из-за проклятия высокой размерности.

Чтобы избежать проблемы высокой размерности, все открытые анализы либо исключали столбец с продуктом, либо столбец с пользователем, либо оба вместе. Исключение столбца с продуктом означает, что я хочу предсказывать поведение пользователей в определенной категории продуктов, а исключение столбца с пользователем означает, что я хочу предсказать продажу определенного продукта для группы пользователей, которые имеют определенные демографические характеристики. Если исключены и столбец с продуктом, и столбец с пользователем, это означает, что я хочу предсказать покупку определенной категории продуктов в определенной группе пользователей. Вы можете видеть, что это совсем не прогноз отдельного пользователя на отдельный продукт. Без четкого понимания цели, вся работа будет провалена.

Синдром Kaggle

Я заметил, что все открытые анализы не удалось на старте: они не старались достаточно узнать цель набора данных. Они ограничивают свой EDA только тренировочными данными, не расширяя анализ до тестового набора, и рассматривают задачу как обычную регрессию, не полностью понимая ее. Я обнаружил, что это общая проблема в Kaggle.

Я был энтузиастом Kaggle в начале своего пути в машинном обучении, но мой интерес быстро угас. Все равно время от времени я просматриваю Kaggle в поисках технических идей, но больше не являюсь его большим поклонником. Одна из причин в том, что я не мог занять высокое место в рейтинге участников. Другая причина в том, что я нашел, что стиль соревнований Kaggle несовместим с практиками машинного обучения в реальном мире.

Каждый участник Kaggle сосредоточен на извлечении последней капли производительности из своих моделей. В реальном мире приоритет полностью обратный: доставка бизнес-значения является гораздо более важным приоритетом. Во многих случаях производительность модели является менее важным требованием. Если ваша модель хорошо вписывается в бизнес, никто не будет задавать вопросы, почему точность составляет 0,95, а не 0,96, если только производительность не является ключевой для проекта. Проекты, в которых производительность модели является критически важной, встречаются редко.

Еще одна проблема с соревнованиями – это отсутствие взаимодействия. После того, как набор данных получен, все. Участникам мало шансов задать вопросы или изменить требования. Как в случае с набором данных Black Friday, мы можем наблюдать некоторые интересные закономерности; однако, мы не можем узнать, почему они возникают и тем более использовать их. В реальных проектах задавание вопросов – самая простая стратегия, чтобы предотвратить провал вашего проекта.

Более того, соревнования Kaggle приучают нас к отсутствию связи с бизнес-контекстом.

Я знаю, что некоторые работодатели нанимают победителей соревнований Kaggle. Это одна из стимулирующих факторов для участников. Однако, я боюсь, что машинное обучение в стиле Kaggle может быть вредным для реального бизнеса. Примером такой ситуации является Zillow. Zillow спонсировал соревнование Kaggle по предсказанию стоимости жилья и предложил работу победителям. Zillow получил множество выгод от машинного обучения, когда рынок недвижимости постоянно рос. Однако, когда рынок недвижимости изменился, Zillow почти обанкротился.

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

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

Регрессия, которая работает

Посмотрим, как мы можем реализовать обычную модель регрессии, чтобы приблизиться к тому, что нам нужно. Как мы обсуждали, одна из основных проблем с персонализацией в общем подходе регрессии – это высокоуровневые измерения. Традиционное одноразрядное кодирование не работает. Метка кодирования не выглядит хорошо, потому что она предполагает, что метка характеристики имеет упорядоченную связь с целью. Мы также не любим создание групп или хэширование. Давайте попробуем другой подход: кодирование по целевому признаку.

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

Перед тем, как приступить к обучению модели, мы приводим все 11 признаков к категориальным и применяем кодирование по целевому признаку для каждого из них. Также мы преобразуем целевую переменную с помощью функции sqrt(), чтобы нормализовать ее, а затем масштабируем целевую переменную в диапазоне от [0.0, 10.0], поскольку некоторые алгоритмы, с которыми я экспериментировал, имеют ограничение, принимающее только значения целевой переменной в этом диапазоне.

Код выглядит следующим образом:

# Train_test_splitingX_train, X_test, y_train, y_test = train_test_split(df_blackfriday_data.drop('Purchase', axis=1), df_blackfriday_data['Purchase'], random_state=random_seed, test_size=0.25)print(X_train.shape, y_train.shape)print(X_test.shape, y_test.shape)# Target encodingfrom category_encoders import TargetEncoderencoder = TargetEncoder()enc = encoder.fit(X=X_train, y=y_train)df_train_X = enc.transform(X_train)df_test_X = enc.transform(X_test)# Model trainingxgb_reg = XGBRegressor( seed=random_seed)xgb_reg.fit(df_train_X, y_train)xgb_y_pred = xgb_reg.predict(df_test_X)print('Scaled RMSE:', sqrt(mean_squared_error(y_test, xgb_y_pred)))print("RMSE on the original test data is ",sqrt(mean_squared_error((y_test*15 + 3.464)*(y_test*15 + 3.464), (xgb_y_pred*15 + 3.464)*(xgb_y_pred*15 + 3.464))))

Вышеуказанный фрагмент кода выдает два значения RMSE: масштабированное RMSE относительно преобразованной целевой переменной и RMSE относительно исходной целевой переменной. Полученные результаты выглядят следующим образом:

Scaled RMSE: 0.8845836109788747

RMSE on the original test data is 2522.1269855375003

Его результаты превосходят все результаты открытого анализа. Из графика важности признаков мы можем ясно понять причину:

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

Персонализация

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

Самый классический подход к анализу рекомендаций и персонализации — это коллаборативная фильтрация. Другими словами, она оценивает сходство между пользователем и пользователем или товаром и товаром для прогнозирования предпочтений пользователей. Вы часто видите графики, подобные следующим, если гуглить рекомендации или коллаборативную фильтрацию, потому что идеи были изобретены во время конкурса по рекомендации фильмов. В этом сценарии концепции — пользователь, фильм и рейтинг, что эквивалентно пользователю, товару и покупке в нашем случае.

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

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

from fastai.collab import CollabDataLoaders, collab_learner# сформируем user-item-rating dataframe ratings_dict = {'item': list(trainset.Product_ID),                'user': list(trainset.User_ID),                'rating': list((trainset.Purchase.pow(1/2)- 3.464)/15)}ratings = pd.DataFrame(ratings_dict)ratings_test_dict = {'item': list(testset.Product_ID),                'user': list(testset.User_ID),                'rating': list((testset.Purchase.pow(1/2) -3.464)/15)}ratings_test = pd.DataFrame(ratings_test_dict)# обучение моделькиlearn = collab_learner(dls, n_factors=160, use_nn=True, y_range=(0, 10))import warningswith warnings.catch_warnings():    warnings.simplefilter("ignore")    learn.fit_one_cycle(5, 5e-3, wd=0.1)# оценкаdl = learn.dls.test_dl(ratings_test, with_labels=True)with warnings.catch_warnings():    warnings.simplefilter("ignore")    aaa = learn.get_preds(dl=dl)    aaatestset['y'] = (testset['Purchase'].pow(1/2) -3.464)/15testset['y_pred'] = [x.tolist()[0] for x in aaa[0]]# testset['y_pred'] = testset['y_pred']*testset['y_pred']*225from sklearn.metrics import mean_squared_errorfrom math import sqrtprint('Масштабированная RMSE', sqrt(mean_squared_error(testset['y'], testset['y_pred'])))testset['Purchase_pred'] = (testset.y_pred*15 +3.464) * (testset.y_pred*15 +3.464)print('RMSE на исходном тестовом наборе', sqrt(mean_squared_error(testset['Purchase'], testset['Purchase_pred'])))

Результат был следующим:

Масштабированная RMSE 0.8624311160502426

RMSE на исходном тестовом наборе 2460.1524061340824

Этот результат значительно лучше предыдущей модели XGBoost на основе таргет-кодирования пользовательского идентификатора и идентификатора товара. Обученная модель нейронной сети невероятно проста:

Модель использует эмбеддинг для преобразования идентификаторов пользователя и товара и использует только один линейный слой. Возможно, вы задаетесь вопросом, почему нам приходится отбрасывать все свойства пользователя и информацию о товаре. Можем ли мы включить все эти функции при прогнозировании?

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

Прощальные слова

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

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

Справочные данные

Черная пятница

Kaggle – крупнейшее сообщество по науке о данных с мощными инструментами и ресурсами, чтобы помочь вам достичь ваших данных…

www.kaggle.com