Ученый Udacity Data Scientist Nanodegree Capstone Project

1. Введение

Sparkify - это вымышленный сервис потоковой передачи музыки, созданный Udacity, чтобы напоминать реальные наборы данных, созданные такими компаниями, как Spotify или Pandora. Миллионы пользователей ежедневно воспроизводят свои любимые песни с помощью сервисов потоковой передачи музыки, либо с помощью бесплатного тарифного плана, который воспроизводит рекламу, либо с использованием модели подписки премиум-класса, которая предлагает дополнительные функции и, как правило, без рекламы. Пользователи могут обновить или понизить свой план подписки в любое время, но также полностью отменить его, поэтому очень важно убедиться, что услуга им нравится.

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

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

1.1 Обзор проекта

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

Чтобы помочь нам достичь нашей цели, Udacity предоставил нам большой набор данных смоделированных журналов активности пользователей Sparkify. Из-за размера набора данных проект был реализован с использованием возможностей распределенной инфраструктуры кластерных вычислений Apache Spark с использованием Python API для Spark, PySpark.

Чтобы упростить процесс разработки модели, большинство шагов, таких как понимание данных, разработка функций и выбор модели, были выполнены на репрезентативной выборке (1/100) полного набора данных Sparkify с использованием Spark в local режим. Модели, которые хорошо работали на меньшей выборке, были обучены и протестированы также на полном наборе данных Sparkify (12 ГБ). Из-за его размера это невозможно было сделать локально, поэтому для выполнения задач в облаке AWS был развернут кластер Elastic MapReduce (EMR).

1.2 Основные шаги

Процесс разработки модели состоит из трех основных этапов, которые можно резюмировать следующим образом.

Понимание данных

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

Разработка функций и исследовательский анализ данных

  • преобразование исходного набора данных (одна строка на журнал пользователя) в набор данных с информацией или статистикой на уровне пользователя (одна строка на пользователя), полученный посредством сопоставления (например, пол пользователя, начало / конец периода наблюдения и т. д.) ) или агрегирование (например, количество песен, количество рекламных объявлений и т. д.)
  • разработка функций, используемых для выявления уволенных пользователей, например агрегированная статистика за единицу времени, количество изменений плана, соотношение прослушанных песен к общей активности, соотношение "Нравится" и "Не нравится", тенденция активности и т. д.
  • определение и вычисление переменной двоичного ответа: 1 - пользователи, которые отменили свою подписку в течение периода наблюдения, и 0 - пользователи, которые сохранили услугу в течение всего периода.
  • анализ корреляции между спроектированными функциями
  • выполнение исследовательского анализа данных, сравнение созданной статистики для пользователей, которые остались, и пользователей, которые ушли

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

  • определение конвейеров, которые объединяют: стандартизацию числовых функций, сборку элементов и выбранный двоичный классификатор (логистическая регрессия, классификатор случайного леса или классификатор повышения градиента)
  • разделение набора данных на обучающий и тестовый набор
  • обучение и настройка конвейера с использованием поиска по сетке с перекрестной проверкой обучающих данных
  • анализ производительности модели при перекрестной проверке (с использованием метрики AUC) и извлечение важности функций
  • повторное обучение наиболее эффективных моделей на полном обучающем наборе и оценка производительности модели на тестовом наборе с использованием показателей AUC и F1

Вышеупомянутые шаги описывают сквозной процесс разработки модели, который выполнялся на меньшем наборе данных Sparkify. Эти шаги подробно описаны в разделах 2–4 ниже. Как уже упоминалось, хорошо работающие модели в конечном итоге были обучены и протестированы также на полном наборе данных Sparkify. Это было сделано простым повторным запуском разработанного кода на полном наборе данных с использованием кластера EMR. Соответствующие результаты представлены в разделе 5.

1.4 Показатели производительности

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

2. Понимание данных

Для поддержки этого проекта были предоставлены два набора данных об активности пользователей Sparkify: полный набор данных sparkify_event_data.json размером 12 ГБ и его меньшее (128 МБ) подмножество mini_sparkify_event_data.json. Мы использовали последний для большинства шагов понимания данных, однако несколько запросов были выполнены также для полного набора данных для подтверждения наблюдаемых свойств.

2.1 Описание данных

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

Согласно нашему анализу, набор данных Sparkify содержит журналы активности пользователей, записанные с 1 октября 2018 года по 30 ноября 2018 года. Полный набор данных состоит примерно из 26 миллионов строк / журналов, тогда как подмножество содержит 286500 строк. Полный набор данных включает журналы 22277 различных пользователей, тогда как подмножество охватывает действия только 225 пользователей. Оба набора данных содержат 18 столбцов, как указано ниже.

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

  • userId (строка): идентификатор пользователя;
  • firstName (строка): имя пользователя.
  • lastName (строка): фамилия пользователя.
  • пол (строка): пол пользователя; 2 категории (M и F)
  • location (строка): местоположение пользователя.
  • userAgent (строка): агент, используемый пользователем для доступа к потоковой службе; 57 разных категорий
  • registration (int): отметка времени регистрации пользователя.

Еще одна информация на уровне пользователя, но не статическая, - это уровень подписки пользователя на момент записи журнала:

  • level (строка): уровень подписки; 2 категории (бесплатные и платные)

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

  • ts (int): отметка времени данного журнала.
  • страница (строка): тип взаимодействия (страница, доступная в приложении для потоковой передачи музыки); 22 категории (NextSong, Home, Login, Подтверждение отмены и т. Д.)
  • auth (строка): уровень аутентификации; 4 категории (Выполнен вход, Вышел из системы, Отменено, Гость)
  • sessionId (int): сеанс, которому принадлежит журнал.
  • itemInSession (int): количество журналов в данном сеансе
  • метод (строка): метод HTTP-запроса; 2 категории (GET и PUT)
  • status (int): код статуса http; 3 категории (200, 307 и 404)

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

  • song (строка): название песни
  • исполнитель (строка): имя исполнителя
  • length (double): продолжительность песни в секундах.

2.2 Примечания и наблюдения

Анализируя различные столбцы, а также их отношения, мы сделали следующие наблюдения об импортированном наборе данных:

  • в наборе данных нет повторяющихся журналов
  • все строки с пропущенными значениями в столбце userId (и вся остальная информация на уровне пользователя) соответствуют журналам, в которых ни один пользователь не вошел в систему (Выход из системы и гостевой уровни аутентификации)
  • Уровень аутентификации Отменено напрямую соответствует типу действия Подтверждение отмены в столбце страница.
  • отсутствуют отсутствующие значения sessionId
  • sessionId однозначно идентифицирует сеанс только в журналах активности определенного пользователя (т. е. конкретный идентификатор сеанса может использоваться для маркировки сеансов нескольких разных пользователей)
  • максимальный временной интервал между двумя последовательными журналами, которые все еще принадлежат одному сеансу, составляет один час
  • функции на уровне песни song, artist и length иметь непропущенные значения только для типа взаимодействия NextSong (отображается в столбце страница)
  • в наборе данных есть пары имени исполнителя и названия песни, длина которых не уникальна (возможно, это связано с переизданием песен)
  • http метод и статус по сути являются сопоставлениями / группировками категорий на странице (например, статус 404 напрямую соответствует значению Ошибка в столбце страницы)

2.3 Интересные визуализации

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

  • пол:. Интересно отметить, что, хотя в анализируемом наборе данных Sparkify (подмножество) больше мужчин-пользователей, значительно выше доля журналов активности, поступающих из женское население.

  • уровень. Пользователи могут переключаться между бесплатной и платной подпиской в ​​любое время. Мы проанализировали для каждого пользователя, сколько взаимодействий он / она совершил в рамках бесплатного плана по сравнению со всеми взаимодействиями как в бесплатном, так и в платном плане. Из гистограммы ниже мы видим, что большинство пользователей, похоже, придерживаются своего плана подписки на протяжении всего периода наблюдения.

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

3. Разработка функций и исследовательский анализ данных

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

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

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

3.1 Преобразования исходного набора данных

а) Период наблюдения для конкретного пользователя

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

Начало наблюдения: отметки времени регистрации пользователей указаны в столбце registration в наборе данных, но мы заметили, что они не всегда кажутся правильными. Для тех немногих пользователей, которые зарегистрировались после 1 октября, время регистрации не соответствует фактическим отметкам времени в журнале и типам действий. Таким образом, нам пришлось идентифицировать позднюю регистрацию, найдя журналы Submit Registration в столбце page. Этот шаг был нетривиальным, поскольку такие события журнала не сопоставляются ни с каким userId, поэтому их нужно было извлечь из информации sessionId.

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

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

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

б) Последний уровень подписки

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

c) Удаление строк без информации об идентификаторе пользователя

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

г) Удаление строк с отметками времени за пределами предполагаемого периода наблюдения по умолчанию.

Импортированный набор данных включает в себя несколько поврежденных записей журнала с отметками времени, значительно превышающими период наблюдения по умолчанию. Такие строки встречаются крайне редко, но убрать их все равно стоило.

3.2 Отображение и агрегирование

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

Недавно созданный набор данных на уровне пользователя включает следующие столбцы:

  • userId
  • lastlevel: последний уровень подписки пользователя, преобразованный в двоичный формат (1 - платный уровень, 0 - бесплатный уровень).
  • пол: пол, преобразованный в двоичный формат (1 - женский, 0 - мужской).
  • obsstart, obsend: начало и конец периода наблюдения за пользователем.
  • endstate: последнее взаимодействие пользователя за период наблюдения.
  • nact: общее количество взаимодействий пользователя за период наблюдения.
  • nsongs, ntbup, ntbdown, nfriend, nplaylist, ndgrade, nupgrade, nhome, nadvert, nhelp, nsettings, nerror: количество проигранных песен, поставленные большие пальцы вверх и вниз. , добавлены друзья, песни, добавленные в список воспроизведения, переход на более раннюю версию, обновления, посещения домашней страницы, просмотренные рекламные объявления, посещения справочной страницы, посещения настроек, ошибки, соответственно
  • nact_recent, nact_oldest: активность пользователя за последние и первые k дней окна наблюдения, соответственно.
  • nsongs_recent, nsongs_oldest: песни, сыгранные за последний и первый k дней окна наблюдения, соответственно

3.3. Функциональная инженерия

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

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

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

а) Числовые характеристики

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

Общая статистика активности за час

  • nact_perh: количество взаимодействий пользователя в час, рассчитанное как {nact_perh = nact / obshours}, где nact представляет общее количество взаимодействий пользователя и наблюдений продолжительность периода наблюдения за пользователем в часах;
  • nsongs_perh, ntbup_perh, ntbdown_perh, nfriend_perh, nplaylist_perh, nhome_perh, nadvert_perh, nhelp_perh, nerror_perh: количество композиций, воспроизводимых в час, количество положительных и отрицательных оценок в час, количество добавленных друзей час, песни, добавляемые в список воспроизведения, за час, посещения домашней страницы за час, реклама воспроизводимых за час, посещений справочной страницы за час, ошибок за час (все рассчитывается так же, как nact_perh выше);

Соотношение видов деятельности

  • songratio: количество воспроизведенных композиций относительно всех действий пользователя, рассчитывается как {𝑛𝑠𝑜𝑛𝑔𝑠 / 𝑛𝑎𝑐𝑡}
  • positiveratio: количество положительных взаимодействий относительно всех взаимодействий с пользователем, рассчитывается как {(ntbup + nfriend + nplaylist) / nact}, где ntbup, nfriend и nplaylist представляют количество поднятых вверх больших пальцев, добавленных друзей и добавленных песен в список воспроизведения соответственно;
  • negativeratio: количество отрицательных или неприятных взаимодействий относительно всех взаимодействий, рассчитывается как {(ntbdown + nhelp + nerror + nsettings) / nact} , где ntbdown, nhelp, nerror и nsettings представляют количество поставленных отметок "Нравится", посещений справочной страницы, ошибок. и посещения страницы настроек соответственно;
  • updownratio: соотношение между количеством поднятых и опущенных больших пальцев для данного {ntbup / (ntbdown + 0.1)}
  • повышенная версия: общее количество изменений плана подписки, рассчитывается как {nugrade + ndgrade}, где nugrade - это число. количества переходов с бесплатного на платный план и ndgrade количества переходов на более раннюю версию;

Тенденции

  • trend_act: тенденция активности пользователя, рассчитываемая как {(nact_recent (k) - nact_oldest (k)) / (k × obshours)}, где nact_recent (k) и nact_oldest (k) представляют количество взаимодействий пользователя со службой за последние и первые k дней (по умолчанию k = 14) окна наблюдения соответственно (разница в активности также масштабируется с длиной окна наблюдения);
  • trend_songs: тренд воспроизведения песни пользователя, рассчитываемый как {(nsongs_recent (k) - nsongs_oldest (k)) / (k × obshours)}, где nsongs_recent (k) и nsongs_oldest (k) подсчитывают, сколько песен сыграл пользователь за последние и первые k дней (по умолчанию k = 14 ) окна наблюдения соответственно (разница в активности масштабируется с длиной окна наблюдения);

Модели взаимодействия

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

  • avgsessionitems: среднее количество взаимодействий пользователя в данном сеансе (напомним, два последовательных журнала относятся к одному и тому же сеансу, если между ними меньше часа);
  • avgsessiontime: средняя продолжительность сеанса пользователя;
  • avgsongs: среднее количество песен, воспроизведенных пользователем между двумя последовательными посещениями главной страницы.

б) Категориальные признаки

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

3.4 Переменная двоичного ответа

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

  • label: двоичная переменная ответа, где: → 1 представляет уволенных пользователей, которые отменили подписку (независимо от плана подписки, бесплатную или платную) в течение период наблюдения с 1 октября по 30 ноября, а → 0 представляет пользователей, которые поддерживали сервис потоковой передачи музыки на протяжении всего периода наблюдения.

Мы получили двоичный ответ от переменной endstate (объясненной в разделе 3.2), в которой хранится последнее взаимодействие пользователя со службой. Для уволенных пользователей Подтверждение отмены - это их последнее взаимодействие с сервисом.

Из приведенного ниже графика легко увидеть, что предоставленный набор данных Sparkify является случаем несбалансированного набора данных, поскольку доля уволенных пользователей составляет лишь немногим более 20% (справедливо для обоих подмножеств и полный набор данных Sparkify).

3.5 Исследовательский анализ данных

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

а) Корреляция характеристик

Как ясно видно из тепловой карты ниже, существует высокая корреляция между большей частью агрегированной статистики активности. Например, переменные nact_perh и nsongs_perh почти идеально коррелированы. Это ожидаемо, поскольку прослушивание песен, безусловно, является наиболее частым действием пользователя (примерно 80% всех взаимодействий). По той же причине существует высокая корреляция между trend_act и trend_songs. В обоих случаях мы решили просто удалить из всех дальнейших анализов (и модели) обе статистические данные, которые измеряют общую активность, и оставить только переменные, которые измеряют наиболее важное взаимодействие - воспроизведение песен.

Чтобы еще больше уменьшить многоколинеарность данных, мы также решили не использовать nhome_perh и nplaylist_perh. в модели. Более того, avgsessionlength сильно коррелирует со средними показателями в каждом сеансе, поэтому его тоже можно игнорировать.

б) Исследовательский анализ данных

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

  • в среднем уволенные пользователи играли больше песен в час;
  • отталкивающие пользователи оставляли значительно больше «не нравится» в час, и им в среднем приходилось смотреть больше рекламы;
  • соотношение песен и положительных взаимодействий по отношению к общей активности обычно было ниже у уволенных пользователей.
  • уволенные пользователи в среднем меньше взаимодействовали за сеанс
  • процент оттока выше для пользователей бесплатного плана подписки
  • процент оттока пользователей-мужчин немного выше

На основании этого анализа никакие функции не были удалены.

4. Моделирование и оценка

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

Используя возможности машинного обучения Spark, мы сначала определили конвейеры, которые объединяют: этап стандартизации, объект ассемблера функций и один из двоичных классификаторов, поддерживаемых Spark. Для каждого из конвейеров мы выполнили поиск по сетке с перекрестной проверкой, чтобы проверить производительность нескольких комбинаций параметров, все на данных пользовательского уровня, полученных из меньшего набора данных об активности пользователей Sparkify. На основе результатов производительности, полученных при перекрестной проверке (измеренных с помощью AUC), мы определили наиболее эффективные экземпляры модели и повторно обучили их на всем обучающем наборе. В конечном итоге мы оценили их производительность на тестовом наборе, используя стандартные метрики двоичной классификации, такие как AUC и F1.

Основываясь на результатах, полученных на меньшем наборе данных Sparkify, мы выбрали подмножество моделей с хорошей производительностью для обучения и тестирования на полном наборе данных Sparkify 12 ГБ с использованием кластера Amazon EMR. В то время как обучение моделей на меньшем наборе данных страдает небольшой проблемой выборки (набор данных сокращается до 225 пользователей, 46 в наборе тестов) и может возвращать довольно нестабильные результаты производительности, полные данные Sparkify (объединяют журналы более 20к пользователей) позволили нам по-настоящему проверить эффективность разработанных моделей. Соответствующие результаты представлены в разделе 5 ниже.

4.1 Трубопроводы

Мы создали три разных объекта Pipeline для трех двоичных классификаторов, поддерживаемых в Spark: Логистическая регрессия, Классификатор случайного леса и Древовидный классификатор с градиентным усилением. Напомним, что набор данных входного объекта состоит из:

  • 14 числовых функций: nsongs_perh, ntbup_perh, ntbdown_perh, nfriend_perh, nadvert_perh, nerror_perh, upgradeowngrade, songratio, positiveratio, negativeratio , updownratio, trend_songs, avgsessionitems, avgsongs (обратите внимание, что некоторые из специально разработанных функций были удалены как часть корреляционный анализ)
  • 2 бинарные функции: lastlevel и пол.

Каждый конвейер объединяет следующие три объекта (см. Снимок ниже):

  1. StandardScaler, который стандартизирует числовые функции.
  2. VectorAssembler, который объединяет их с двоичными функциями (уже преобразованными в 0/1, поэтому никаких дополнительных преобразований не требуется)
  3. выбран бинарный классификатор с параметрами по умолчанию (параметры все равно передаются при поиске по сетке)

4.2 Объекты поиска по сетке

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

а) Логистическая регрессия

  • maxIter (максимальное количество итераций, по умолчанию = 100): [10, 30]
  • regParam (параметр регуляризации, по умолчанию = 0,0): [0,0, 0,1]
  • elasticNetParam (параметр смешивания - 0 для штрафа L2, 1 для штрафа L1, по умолчанию = 0,0): [0,0, 0,5]

б) Классификатор случайного леса

  • maxDepth (максимальная глубина дерева, по умолчанию = 5): [4, 5, 6, 7]
  • numTrees (количество деревьев, по умолчанию = 20): [20, 40]

c) Древовидный классификатор с градиентным усилением

  • maxDepth (максимальная глубина дерева, по умолчанию = 5): [4, 5]
  • maxIter (максимальное количество итераций, по умолчанию = 20): [20, 100]

В определенных объектах поиска в сетке эффективность каждой комбинации параметров по умолчанию измеряется средней оценкой AUC (область под ROC), полученной при 4-кратной перекрестной проверке. Краткое описание AUC приводится в разделе 4.4 ниже.

Во время разработки модели мы также реализовали показатель F1 в качестве альтернативного настраиваемого оценщика перекрестной проверки, поскольку во встроенном оценщике Spark только AUC (площадь под ROC) и PR AUC (площадь под кривой точности-отзыва) ) реализованы. Мы заметили, что перекрестная проверка с F1 не привела к серьезным различиям с точки зрения ранжирования между тестируемыми моделями, поэтому мы просто работали с AUC по умолчанию. Реализованный оценщик оценок F1 использовался для оценки модели на тестовом наборе (см. Раздел 4.4).

4.3 Разделение данных обучения / тестирования

Мы разделили набор данных на уровне пользователя на набор для обучения и тестирования, используя соотношение 80/20. Строго говоря, обучающий набор также включает данные проверки, поскольку они используются в 4-кратной перекрестной проверке, выполняемой на каждом этапе поиска по сетке.

4.4 Модельное обучение и оценка

Для каждого из трех определенных двоичных классификаторов / конвейеров были выполнены следующие шаги:

  1. выполнить поиск по сетке с 4-кратной перекрестной проверкой путем подгонки определенного объекта CrossValidator к обучающим данным
  2. определить комбинации параметров, которые возвращают лучший средний AUC при перекрестной проверке
  3. переобучить лучший экземпляр модели на всем обучающем наборе
  4. если применимо, проанализируйте важность функций
  5. оценить выбранный экземпляр модели на тестовом наборе, используя показатели AUC и F1.

Показатели эффективности

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

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

4.5. Сводка результатов

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

AUC относительно высок для всех трех моделей, особенно для классификатора случайных лесов, а также для классификатора деревьев с градиентным усилением. Результаты F1 показывают значительно более слабую производительность, и только метод повышения градиента дает твердые 0,545. Однако, поскольку показатели AUC высоки, весьма вероятно, что мы могли бы существенно увеличить показатель F1 в наборе тестов, оптимизируя порог вероятности, который разделяет положительные и отрицательные предсказания класса. Вышеуказанные баллы F1 были получены с использованием порога по умолчанию 0,5.

Мы должны подчеркнуть, что эти результаты соответствуют моделям, которые были обучены и протестированы с использованием меньшего набора данных Sparkify, который объединяет журналы активности только 225 уникальных пользователей. Это означает, что модели тестируются на выборке из 46 экземпляров, из которых только около 10 являются положительными классами (в среднем), и это приводит к довольно нестабильным результатам оценки производительности.

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

5. Обучение и тестирование на полном наборе данных Sparkify.

После завершения процесса разработки модели на небольшом подмножестве Sparkify мы повторно использовали разработанные реализации также на полном наборе данных об активности пользователей Sparkify. Набор данных слишком велик для локальной обработки, поэтому для выполнения задач в облаке AWS был развернут кластер Elastic MapReduce (EMR). Из-за бюджетных ограничений, а, следовательно, и из-за вычислительных ограничений, мы не смогли выполнить полномасштабный поиск по сетке для всех выбранных двоичных классификаторов. Поэтому мы просто выбрали подмножество моделей, которые хорошо работали на меньшем наборе данных и для которых, как мы думали, они имеют потенциал сделать это также и на более крупном наборе данных.

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

Чем больше обучающих данных предоставляется классификатору, тем лучше результаты, чем результаты, полученные на меньшем наборе данных. Кроме того, показатели AUC и F1 улучшаются с увеличением количества итераций повышения максимального градиента. Самая эффективная модель имеет показатель AUC 0,981 и показатель F1 0,855.

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

Важность функций

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

Как видно из визуализации ниже, наиболее важной функцией для определения оттока пользователей является nerror_perh, который измеряет, сколько страниц с ошибками было показано пользователю в час. Интуитивно понятно, что чем больше ошибок пользователь должен испытать, тем больше вероятность того, что он / она недовольны услугой. То же самое справедливо и для второй и третьей по важности функции, ntbdown_perh и nadvert_perh, которые измеряют количество опущенных вниз данные за час и количество рекламных объявлений, просмотренных за час, соответственно. Несмотря на все дополнительные вычисления, в набор функций стоило включить также четвертую по важности переменную trend_songs, которая измеряет тенденцию прослушивания песен пользователем.

Две бинарные функции, а именно lastlevel (т. Е. Последний известный уровень подписки) и пол, не имеют большого значения для прогнозирования оттока пользователей.

6. Выводы

Отражение

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

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

Возможные улучшения

Несмотря на хорошие характеристики разработанной модели, есть возможности для дальнейших улучшений:

  • создавать и тестировать функции, которые собирают дополнительную информацию о шаблонах действий пользователя, например средняя продолжительность сеансов прослушивания песен, соотношение пропущенных или частично прослушанных песен и т. д.
  • использовать функции на уровне песни, которые до сих пор игнорировались, например рассчитать разнообразие прослушивания пользователя с точки зрения разных песен / исполнителей, которые слушали за указанный период наблюдения, и т. д.
  • оптимизировать обработку данных и этапы разработки функций, используя передовой опыт Spark, чтобы ускорить обучение и тестирование модели (текущее решение довольно медленное и может плохо масштабироваться)
  • выполнить комплексный поиск по сетке для модели повышения градиента на полном наборе данных Sparkify, используя кластер Amazon EMR

Для получения дополнительных сведений об этом проекте см. Ссылку на мой Github, доступную здесь.