При работе с клиентами возможность предвидеть отток - это одновременно возможность улучшить обслуживание клиентов и показатель того, насколько хорошо работает бизнес.
В центре внимания главного проекта Udacity. Data Science Nanodegree, я решил работать над прогнозированием оттока для службы потоковой передачи музыки под названием Sparkify. Я представляю здесь анализ данных, которые я использовал, и выводы, которые я сделал, а также подход, который я выбрал для реализации.

Контекст проекта

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

В нашем распоряжении есть два набора данных: основной набор данных размером около 12 ГБ и мини-набор данных размером около 128 МБ.
Из-за размера основного набора данных нам необходимо иметь возможность разделить наши данные на несколько кластеров, и мы собираемся реализовать все, используя инфраструктуру Spark вместо традиционных Pandas / Библиотеки Scikit-Learn с Python.

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

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

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

Очистка данных и определение оттока

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

Мы замечаем несколько важных вещей:

  • есть два типа столбца: числовой и категориальный
  • Пол имеет нулевое значение - ›мы должны избавиться от соответствующих строк, поскольку они, скорее всего, не связаны ни с одним пользователем (и мы хотим строить прогнозы на основе поведения пользователя!)
  • userId имеет в качестве значения пустую строку - ›мы должны избавиться от соответствующих строк
  • userAgent и метод не кажутся подходящими функциями для просмотра
  • auth имеет статус "Отменено", который может быть полезен позже для просмотра показателей оттока
  • количество уникальных пользователей (226) и уникальных местоположений (115), как правило, указывает на то, что население широко распространено в нескольких городах, и эта функция может не иметь большого значения для прогнозирования оттока (мы будем подтвердите это при более глубоком изучении набора данных)
  • похоже, что подавляющее большинство набора данных состоит из действия «NextSong» (около 80%). И столбцы «Исполнитель» и «Песня» заполняются только тогда, когда в столбце страницы указано значение «NextSong». Однако в оставшихся 20% строк (Upgrade, Home,….) Мы не ожидаем найти исполнителя или Song, что составляет около 57000 строк.

Теперь давайте сосредоточимся на недостающих или недействительных данных.

Около 8346 строк не содержат userId или sessionID и поэтому не используются для нашей цели прогнозирования. Это количество строк составляет менее 3% набора данных, поэтому мы можем просто удалить их.
Обратите внимание, что в столбцах "исполнитель" и "песни" намного больше отсутствует ценности. Это связано с тем, что характер записей заключается не только в воспроизведении песни, но и в входе в службу, переходе на домашнюю страницу… и, как мы видели, около 20% строк не должны содержать ни одного исполнителя. или значения песни.

Этот этап очистки довольно прост:

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

Наконец, мы должны определить что означает отток. Здесь есть два подхода:

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

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

Исследование данных

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

Также обратите внимание, что когда мы говорим о среднем, если это не указано явно, оно рассчитывается для всего мини-набора данных, поэтому данные за два месяца доступны в этом наборе данных.

Вот некоторые из наиболее важных сюжетов и выводы, которые мы сделали из них.

Влияние пола

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

Влияние уровня (платный / бесплатный) пользователя

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

Влияние местоположения пользователя

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

Влияние среднего ежедневного количества песен, которые слушают в неделю

Если посмотреть на среднесуточное количество песен, это выглядит так:

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

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

Влияние среднего количества слушателей разных исполнителей

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

Влияние среднего количества прослушанных повторов

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

Влияние среднего количества просмотренных объявлений

Мы можем наблюдать две тенденции:

  • пользователи, которые отказались от рекламы, слушают в среднем больше рекламы по сравнению с количеством песен, чем активные пользователи.
  • бесплатные пользователи слушают в 10 раз больше рекламы, чем платные пользователи

Влияние количества входов в систему и времени между двумя входами

Похоже, что отмененные отталкивающие пользователи подключаются меньше, чем активные пользователи, хотя разделение не очевидно (тенденция такова, что большинство отменивших отток пользователей подключаются от 1 до 13 раз, в то время как большинство активных пользователей входят от 1 до 22 раз). Что касается оттока пользователей, которые понизили рейтинг, тенденция совершенно иная - некоторые оттесненные пользователи фактически заходили в систему больше раз, чем активные платные пользователи!

Из этого графика видно, что отталкиваемые пользователи на самом деле подключаются более регулярно, чем активные пользователи!

Влияние времени прослушивания на сеанс

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

Здесь мы наблюдаем, что большинство людей слушают менее 20 минут музыки за сеанс, при этом активные пользователи имеют тенденцию слушать больше.

Влияние времени активности (количество действий)

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

Влияние времени между регистрацией, обновлением и переходом на более раннюю версию

Мы можем наблюдать, чем в среднем:

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

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

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

Исследование данных позволило нам понять несколько вещей:

  • Активные пользователи, как правило, больше присутствуют на музыкальном сервисе, чем уволенные пользователи (больше песен, повторов, диктуют исполнителей…)
  • Понижение и отмена оттока пользователей ведут себя по-разному для некоторых показателей. Бывает, что оттесненные пользователи с пониженным рейтингом, кажется, больше присутствуют в сервисе, чем активные платные пользователи - им настолько нравится сервис, что они фактически продолжат использовать его, несмотря на дополнительные ограничения, связанные с тем, чтобы быть бесплатным пользователем, любят слушать больше рекламы (они переходят на более раннюю версию и попадают в категорию бесплатных активных пользователей).
  • Время регистрации может быть индикатором типа пользователя, а также того, когда люди активны (в основном в будние дни) - поэтому профиль пользователей отличается, возможно, пользователи, которые слушают музыку на работе. , в то время как отталкиваемые пользователи больше проводят время в свободное время, может быть, они также более требовательны и, следовательно, более склонны к оттоку?
  • Местоположение или пол не соответствовали критериям

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

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

Эти расчеты отклонений направлены на наблюдение за изменениями в поведении пользователя, придавая другой вес более старым событиям по сравнению с более недавними событиями. Однако, поскольку мы не можем изначально сказать, какие веса лучше, мы собираемся определить логику, чтобы иметь возможность регулировать эти веса, учитывая несколько сценариев (мы могли бы попробовать, например, для недавних / старых следующих весов 0,8 / 0,2, 0,5 / 0,5, 0,6 / 0,4, что означает, что последние события составляют 80% значения, а более старые события - 20%).

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

Чтобы обработать эту логику, мы определили:

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

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

В конце этого процесса мы сохраняем сводку на коэффициент отклонения (так что всего 3 сводки сохранены в данных мини-набора данных).

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

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

Целью этого этапа анализа является:

  • определение с коэффициентом отклонения имеет больше смысла
  • выберите наиболее эффективную модель после настройки гиперпараметров

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

Прогнозирование оттока услуг

Если мы сначала посмотрим на влияние коэффициентов отклонения, вот оценка F1, которую мы получаем без какой-либо настройки гиперпараметров.

Мы можем заметить, что:

  • вообще говоря, соотношение 60/40 не дает таких хороших результатов, как два других соотношения
  • в целом соотношение 80/20 дает наилучшие результаты для двух моделей, которые работают лучше (логистическая регрессия и дерево с градиентным усилением)

После запуска CrossValidator с ParamGrid мы обнаружили, что лучшей комбинацией было Gradient Boosted Tree с {'maxDepth': 3, 'maxBins': 50, 'maxIter': 250, 'stepSize': 0,1} при коэффициенте отклонения 70/30 с баллом F1 87%. После того, как мы запустили набор для проверки, мы получили окончательную оценку 83%.

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

Прогноз оттока клиентов на более раннюю версию

Мы проделали точно такие же шаги и вот выводы, которые мы сделали:

  • Логистическая регрессия и дерево с градиентным усилением работают лучше, чем случайный лес
  • Два отношения отклонения 80/20 и 70/30 также показали лучшие результаты, чем 60/40.
  • Используя CrossValidator и ParamGrid, мы пришли к выводу, что лучшей комбинацией было Gradient Boosted Tree с {'maxDepth': 3, 'maxBins': 50, 'maxIter': 250, 'stepSize': 0,1} при коэффициенте отклонения 70/30 с баллом F1 87%. После того, как мы запустили набор для проверки, мы получили окончательную оценку 83%.

Вывод

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

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

После начальной фазы очистки данных с последующим исследовательским анализом мы разработали функции, позволяющие обучать классификатор. Используя весь потенциал данных временных рядов, мы решили включить функции, которые несут информацию об изменениях поведения пользователя с течением времени. Мы составляем сводку за неделю для каждого пользователя, и некоторые функции рассчитываются на основе значений предыдущей недели, когда пользователь взаимодействовал с сервисом.
Используя наивный подход к сопоставлению старых событий с недавними, мы попробовали несколько коэффициентов отклонения (80/20, 70/30, 60/40).

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

Наши выводы были следующие:
- для оттока услуг лучшей комбинацией является Gradient Boosted Tree с {'maxDepth': 3, 'maxBins': 50, 'maxIter': 250, 'stepSize': 0,1}, при коэффициенте отклонения 70/30, с F1-счетом 83%, до 87%.
- для перехода на более раннюю версию лучшей комбинацией является Gradient Boosted Tree с {'maxDepth' : 3, 'maxBins': 50, 'maxIter': 250, 'stepSize': 0,1}, по коэффициенту отклонения 80/20, с показателем F1 81–82%.

С этого момента мы уже можем предвидеть дальнейшую работу и улучшения:

  • улучшить способ взвешивания старых событий по сравнению с новыми событиями
  • протестируйте модели на более крупном наборе данных (полный набор данных) и наблюдайте за изменениями в производительности и результатах
  • расширить работу, чтобы предсказать, КОГДА пользователь перестанет работать (например, с помощью фильтров Калмана)
  • преобразовать код в сценарий, который можно развернуть в любой среде Spark
  • реализовать конвейер для автоматического пересчета прогноза с поступлением новых еженедельных данных, с еженедельной задачей для повторного вычисления сводки, переобучения модели и отчета о потенциальных оттоках на основе последних журналов
  • развернуть этот код на кластерах AWS

Все это потенциальные направления, которые следует принять и описать в других сообщениях! Быть в курсе!

Весь мой код доступен в следующем репозитории Github, следуйте подходу в блокноте Jupyter!