Обзор

Проект Sparkify по прогнозированию оттока — это ключевой проект специалиста Udacity Data Scientist Nanodegree. Sparkify, как его еще называют, — это музыкальное приложение. Используемый нами набор данных содержит журнал поведения пользователей sparkify за два месяца. Журнал содержит некоторую основную информацию о пользователе, а также информацию об его действиях в приложении.

Цель

Основная цель проекта — проанализировать и манипулировать большим набором данных с помощью Spark, чтобы найти соответствующие функции, прогнозирующие скорость оттока для вышеупомянутого приложения Sparkify с использованием «простых» моделей машинного обучения, это было бы намного лучше, чем то, что можно было бы сделать с не- распределенные технологии, такие как scikit-learn. В данных часть пользователей уволена, благодаря отмене поведения учетной записи можно различить ушедших и не ушедших пользователей. Оставшаяся часть этой статьи построена следующим образом.

  1. Предварительная обработка данных: очистка данных при необходимости.
  2. Исследовательский анализ данных (EDA): изучение данных.
  3. Разработка функций: создавайте функции для использования во время моделирования.
  4. Моделирование. Создавайте различные модели машинного обучения.
  5. Результаты

Полный набор данных составляет 12 ГБ, но здесь мы проанализируем мини-подмножество размером 128 МБ. Данные содержат 18 функций и 286 500 записей.

Предварительная обработка данных

Прежде чем мы начнем разрабатывать наши функции и строить модель, нам нужно очистить некоторые значения, которые мы не рассматриваем.

UserId и sessionId — это ключевые слова, поведение которых трудно анализировать, если они имеют значение null, поэтому значение null необходимо удалить.

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

Было обнаружено, что из 286 500 записей всего 278 154 верны. Это означает, что около 3% записей были пользователями без активности (не входившими в систему).

Определение ушедших пользователей

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

Функция страницы использовалась для определения измененного населения. Если пользователь взаимодействовал с «Подтверждением отмены», можно с уверенностью сказать, что пользователь больше не использует услугу.

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

Распределение взаимодействий со страницей: отток против активных пользователей

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

Как показано на приведенной выше диаграмме, существует ряд различий в действиях между уволенными и активными пользователями. Более высокая доля активности «палец вниз» у уволенных пользователей свидетельствует о том, что им не понравился контент (музыка) в приложении, что может объяснить меньшее время сеансов и меньшее количество песен, прослушанных за один сеанс. Активные пользователи, как правило, более интерактивны, поскольку они чаще добавляют друзей и нажимают «палец вверх» на контент, тогда как ушедшие пользователи чаще нажимают «палец вниз». Эти характеристики мы можем использовать во время разработки функций.

Разработка функций

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

Разработанные функции следующие:

  1. Пол
  2. Количество дней с момента регистрации
  3. Количество сыгранных песен
  4. Средняя продолжительность сеанса
  5. Среднее количество песен за сеанс
  6. Количество прослушанных певцов
  7. Количество сеансов
  8. Количество друзей на платформе

Всего восемь функций, теперь мы готовы к моделированию.

Моделирование

+-----+-----+
|churn|count|
+-----+-----+
| true|   44|
|false|  162|
+-----+-----+

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

+-----+-----+
|churn|count|
+-----+-----+
| true|   40|
|false|   46|
+-----+-----+

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

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

Гиперпараметры логистической регрессии включают параметры эластичной сети и параметры регуляризации. Подробные гиперпараметры настраиваются следующим образом:

lr =  LogisticRegression()
paramGrid = ParamGridBuilder() \
    .addGrid(lr.elasticNetParam,[0.0, 0.1, 0.5, 1.0]) \
    .addGrid(lr.regParam,[0.0, 0.05, 0.1]) \
    .build()

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

dt = DecisionTreeClassifier()
paramGrid = ParamGridBuilder() \
    .addGrid(dt.impurity,['entropy', 'gini']) \
    .addGrid(dt.maxDepth,[2, 3, 4, 5, 6, 7, 8]) \
    .build()

Ниже мы обсудим результаты для обеих тестовых моделей.

Результаты

Результат не идеален, скорость отзыва модели линейной регрессии не очень хорошая, не отличная, такой же результат для модели дерева решений, а именно 0,75.

Счет F1 отличался, но не настолько. Логистическая регрессия получила оценку 0,66, в то время как древовидная модель тоже оказалась равной 0,6. Мы можем сделать вывод из этого краткого обзора, что мы можем добиться большего успеха в следующем анализе. Улучшение настройки моделей, безусловно, поможет получить более высокий балл и точность F1. Еще одна вещь, которую мы могли бы создать и добавить больше функций.

Гитхаб

https://github.com/windelmm/Sparkify.git