Определение проекта

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

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

Постановка задачи

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

  • Прослушивание песни
  • Добавление друга
  • Вход в систему

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

Отток будет определяться как «клиент, посетивший страницу подтверждения отмены».

Задачи этого проекта:

  1. Загружайте большие наборы данных в Spark и управляйте ими с помощью pythons pyspark API.
  2. Используя фреймы данных Spark, разработайте функции, которые помогут в прогнозировании оттока.
  3. Используйте Spark ML для создания и настройки моделей машинного обучения, которые будут прогнозировать отток.

Метрики

Поскольку мы имеем дело с оттоком, наши ярлыки будут искажены. Количество уходящих пользователей составляет около 10% от всех наших пользователей. Для таких проблем точность не является хорошим показателем, поскольку модель, которую пользователь никогда не откажется, наберет 90%. Чтобы определить, насколько хороша наша модель, нам нужно будет посмотреть на точность, отзывчивость и оценку F1:

  • Точность: сколько из всех предсказанных оттоков действительно верны.
  • Вспомните: сколько клиентов было спрогнозировано с помощью модели.
  • F1-рейтинг: согласованное среднее значение точности и запоминания.

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

Анализ

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

Наши данные представляют собой образец журнала событий за период с октября по ноябрь 2018 г. В наших выборочных данных объемом 128 МБ у нас есть 286500 событий 255 пользователей со следующими 18 функциями:

  • исполнитель: исполнитель воспроизводимой песни. Если событие не касается прослушивания песни, поле не заполнено.
  • auth (аутентификация): независимо от того, вошел ли пользователь в систему, вышел из системы, был отменен или гость.
  • firstName: имя пользователя. Нулевое значение, если пользователь не вошел в систему.
  • пол: пол пользователя (М / Ж), null, если пользователь не вошел в систему.
  • itemInSession: количество событий на данный момент в сеансе. Начинается с 0.
  • lastName: фамилия пользователя. Нулевое значение, если пользователь не вошел в систему.
  • длина: время в секундах, в течение которого была воспроизведена песня. если событие не связано с прослушиванием песни, поле пустое.
  • уровень: есть ли у пользователя платная подписка (платная / бесплатная).
  • местоположение: местоположение пользователя в формате город, штат. Все пользователи из США.
  • страница: страница, на которой произошло событие. В наборе данных существуют следующие страницы: «Отмена», «Отправить на более раннюю версию», «Не нравится», «Домой», «Перейти на более раннюю версию», «Прокрутить рекламу», «Выйти», «Сохранить настройки», «Подтверждение отмены», «О программе», «Отправить регистрацию», «Настройки», «Войти», «Зарегистрироваться», «Добавить в список воспроизведения», «Добавить друга», «Следующая песня». , "Нравится", "Помощь", "Обновить", "Ошибка" и "Отправить обновление".
  • регистрация: регистрационный номер, связанный с каждым пользователем.
  • sessionId: номер инициированного сеанса.
  • песня: название воспроизводимой песни.
  • статус: код статуса HTTP (200, 307, 404).
  • ts: отметка времени в миллисекундах.
  • userAgent: информация об устройстве и браузере, осуществляющем доступ к данным.
  • userId: идентификатор, связанный с каждым пользователем.

А вот пример данных:

В наших данных нет повторяющихся событий, но есть много строк без userId. Это связано с тем, что в событиях перед входом в систему поле пользователя пусто. Некоторые из этих событий могут быть назначены пользователю на основе sessionId. Если в сеансе есть только один пользователь, тогда все события этого сеанса должны принадлежать этому пользователю. Однако только в 2,9% событий отсутствуют идентификаторы пользователя, а во многих сеансах участвует более одного пользователя. Нет никаких непосредственных причин полагать, что эти события необходимы для целей этого проекта, и поэтому они будут исключены в остальной части этого анализа, в результате чего останется 278154 события.

Теперь мы можем посмотреть, сколько пользователей используют сеансы:

Большинство наших пользователей не делятся сеансами с другими пользователями (80%). Однако значительное количество сеансов используется совместно.

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

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

  1. You’re The One - Дуайт Йоакам
  2. Отменить - Björk
  3. Веселье - Короли Леона
  4. Sehr kosmisch - Гармония
  5. Концерт для валторны № 4 ми-бемоль K495: II. Романс (Andante cantabile) - Барри Таквелл / Academy of St Martin-in-the-Fields / сэр Невилл Марринер

Вы можете послушать лучшую композицию здесь. Лучшие художники:

  1. Короли Леона
  2. Холодная игра
  3. Флоренция + Машина
  4. Дуайт Йоакам
  5. Björk

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

Исследовательская визуализация

На рисунке ниже показаны категориальные функции с менее чем 25 категориями.

Большинство наших мероприятий оплачиваются (80%), женщин больше, чем мужчин, и большинство мероприятий (›80%) слушают песни (страница: NextSong, метод: PUT и статус: 200). Единственная числовая функция - «длина». Другие функции могут быть числового типа, но представлять категорию или порядковый номер. Гистограмма ниже показывает распределение признака «длины».

Минимальная длина составляет 0,8 секунды, а максимальное значение
- 3025 секунд. Эти значения явно выбрасываются в распределении, где процентили 0,25 и 0,75 составляют соответственно 205 и
258 с медианным значением 222 с.

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

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

Алгоритмы и техники

Несмотря на то, что размер набора данных, с которым мы будем работать, составляет всего 128 МБ, проблема может быть применена к большим наборам данных, которые требуют использования распределенных систем параллельных процессов. В этом проекте будет использоваться система Spark с использованием Python API Pyspark. Поскольку размер наших данных невелик, мы запустим искровой кластер локально на нашей машине. Вся работа, от извлечения и преобразования данных до настройки моделей, будет выполняться в Spark. Однако мы сохраним преобразованные данные, готовые для обучения, в постоянное хранилище, чтобы ускорить процесс.

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

Отток будет рассматриваться как проблема бинарной классификации. Среди моделей классификации Spark мы ограничим наше исследование тремя моделями:

Мы настроим эти модели и посмотрим на точность, отзыв и F1 (как обсуждалось выше).

Реализация:

Процесс ETL

Данные в этом случае хранятся в файле JSON локально на нашем компьютере, для больших наборов данных данные будут загружаться, вероятно, из облачного хранилища. Данные будут загружены в фрейм данных pyspark с помощью метода сеанса pyspark read.json ().

event_log = spark.read.json('mini_sparkify_event_data.json')

Преобразование данных разделено на четыре этапа:

  1. Очистка данных
  2. Создание новых событийно-ориентированных функций: быстрое кодирование и индексация
  3. Преобразование данных о событиях в пользовательские данные путем агрегирования функций
  4. Сохраните данные преобразования в постоянную память

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

event_log = event_log.where(event_log.userId != '')

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

2. Создание новых функций на основе событий:
На первом этапе следующие функции создаются с помощью пользовательских функций pyspark (udf) и фреймов данных .withColumn () метод.
Для извлечения информации из функции userAgent был установлен пакет ua-parser. Созданные функции:

  • os (строка): операционная система, извлеченная из агента пользователя.
  • browser (строка): используемый браузер, извлеченный из userAgent.
  • платный (целое число): 1 или 0 в зависимости от уровня функции (платный / бесплатный)
  • состояние (строка): состояние из функции местоположения.
  • day (int): день недели, когда произошло событие (от 0 до 6, с понедельника по воскресенье)
  • час (int): час дня, когда произошло событие (от 0 до 23 часов)
  • is_female (int): является ли пользователь женщиной
  • отмена (int): указывает, является ли страница события подтверждением отмены.

Теперь мы будем горячо кодировать следующие функции:

  • os создание функций для iOS, Linux, Ubuntu, Mac OS X, Windows.
  • браузер, создающий функции для Firefox, Safari, Mobile Safari, IE, Chrome.
  • страница, создающая 19 новых функций.
  • state создаст в общей сложности 44 новых функции. У некоторых пользователей отсутствуют значения состояния, которые будут представлены всеми нулями, а у других есть более одного состояния, поэтому они будут представлены более чем одной единицей.

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

  • isWeekend: суббота или воскресенье: день
  • isAfestive: мероприятие было проведено с 12:00 до 12:00.

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

Наконец, будет добавлена ​​функция usersPerSession. Эта функция показывает, сколько разных идентификаторов пользователей имеют общий идентификатор сеанса. Код для создания функции useresPerSession показан ниже:

count_users = udf(lambda l: len(l), IntegerType())
session_user = event_log.select(col(‘sessionId’), event_log.userId.cast(‘float’).alias(‘userId’)) \
 .groupBy(‘sessionId’)\
 .agg(collect_set(“userId”)) 
session_user = session_user.withColumn(“usersPerSession”, count_users(session_user[‘collect_set(userId)’]))
event_log = event_log.join(broadcast(session_user), [“sessionId”], how=’left’)

3. Создание groupBy features:
На этом этапе функции, созданные на шаге 2, будут агрегированы для каждого пользователя следующим образом:

  • По среднему: 'isWeekend', 'isAfestive', 'songRank', 'is_female', 'artistRank', 'usersPerSession', 'length', 'paid', os. функции, функции браузера, функции состояния и page_features. Среднее значение зависимых от пользователя функций, таких как 'is_female' или горячих кодировок для состояния, вернет либо 1, либо 0. Другие, такие как 'платный', вернут долю событий. В случае «оплачено»: доля или события, которые были оплачены. Наконец, числовые функции, такие как «songRank» или «length», будут возвращать среднее значение для этих функций (например, средний рейтинг прослушиваемых исполнителей или средняя длина песни). Nb: функции страницы ‘page_is_cancel’ и ‘page_is_cacellationConfirmation’ будут удалены на этом этапе. их сохранение приведет к поражению цели, поскольку метка наших данных (цель прогнозирования) будет присутствовать в наших функциях прогнозирования.
  • По максимуму: таким образом будут объединены только ‘page_is_CancellationConfirmation’ и ‘ts’. 'max (page_is_CancellationConfirmation)' будет
    нашим значением оттока, а 'max (ts)' будет использоваться позже для расчета времени использования Пользователь.
  • По минимуму: только «ts» будет рассчитываться для получения времени использования пользователем.

Наконец, будут созданы две функции:

  • «totalTime»: рассчитывается как max (ts) - min (ts)
  • «событий в день»: рассчитывается как количество событий на пользователя, разделенное на totalTime.

4. Сохранение преобразованных данных:
На данный момент мы в основном создали группу DAG, которую необходимо оценить. Чтобы облегчить обучение и настройку модели, мы будем вычислять наши характеристики, сохраняя их в постоянной памяти. Сначала мы создадим разреженный вектор с помощью VectorAssembler () со следующими функциями: avg (isWeekend), avg (isAfestive), avg (songRank), avg (is_female), avg ( исполнитель и т. д.)), avg (функции страницы (главная, справка и т. д.)), count, totalTime и events_per_day.

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

Моделирование и настройка

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

  1. Разделите данные на обучающие и тестовые. 25% данных будут использованы в качестве тестовых данных. Мы оценим обученные модели на этих данных, чтобы определить лучшую модель. Поскольку у нас очень мало положительных результатов (около 10%), мы проверим, что оба набора имеют сопоставимое количество положительных меток (отток).
  2. Нам нужно определить подходящих оценщиков, поскольку двоичные оценщики в pyspark не соответствуют нашим потребностям (оценка F1).
  3. Для каждой выбранной модели мы создадим конвейер с min-max скейлером и настроим этот конвейер с помощью pysparks CrossValidator (). Поскольку у нас не так много данных в этом примере, трехкратного перекрестного оценщика будет достаточно. Будут настроены следующие гиперпараметры:

3. Результаты и выводы.

Вот окончательные результаты тюнингованных моделей:

Как видно из результатов, ни одна из моделей не особо хороша. Максимальный балл F1 был получен с классификатором перцептронов (MPC) с 11 уровнями. Логистическая регрессия (LR), похоже, работает аналогично оценке MPC, более низкой как по отзыву, так и по точности. Классификатор случайного леса (RFC), однако, был крайне консервативен, он предсказал только 4 из 16 оттесненных пользователей.

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

Интересно, что характеристики состояния CO, AR и DC занимают наивысшее место. Это может означать, что пользователи в этих состояниях склонны к оттоку больше, чем в других состояниях.
Было бы рискованно делать такие выводы, поскольку существует 44 состояния и 255 пользователей, очень мало пользователей в каждом состоянии, которые могут повлиять на нашу модель.
Если бы размер нашего набора данных был равен размеру исследуемой здесь выборки, мы бы изучили возможность удаления этих функций, однако эта работа
предназначена также для применения к более крупным наборам данных, где эти функции могут снова стать актуальным.

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

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

Теперь мы можем перейти к RFC, рисунок ниже показывает важность функций из 10 лучших:

Как мы видим, он сильно зависит от общего времени. Опять же, это может быть связано с небольшим размером нашего набора данных.

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

Выводы и дальнейшая работа

Представленная здесь работа показывает, как можно спроектировать функции из журналов событий для создания данных, которые будут использоваться в моделях машинного обучения для прогнозирования оттока клиентов. Мы определили отток клиентов в зависимости от того, посетил ли пользователь страницу отмены заказа. Мы использовали образец набора данных в локальном кластере pyspark, который можно легко масштабировать до гораздо более крупных наборов данных (большие данные). Из трех обученных моделей ML наиболее высокий результат F1 получил классификатор Multilayer Perceptron Classifier (MPC). Одним из недостатков MPC является сложность объяснения прогноза по отношению к функциям, однако мы можем взглянуть на логистический регрессор и классификатор случайного леса, чтобы получить некоторое представление о том, какие функции кажутся более важными для прогнозирования оттока. .
Основные функции логистического регрессора связаны с состояниями (местоположением), событием "Нравится", событием "Добавить друга", общим временем и операционной системой Ubuntu.
Верхняя функция классификатора случайного леса на сегодняшний день является общей время, за которым следуют события дня, минус и ранг артиста.

Размер нашего набора данных очень мал, только 255 пользователей были использованы для обучения с перекрестной проверкой и тестирования моделей. Это влияет на способность моделей к обобщению и прогнозированию, полученные нами оценки были довольно низкими, 0,54 F1-балла в MPC. Выбор модели, в конце концов, будет зависеть от деталей мер, применяемых к предварительным оттокам пользователей. Дорогостоящие меры по ложным срабатываниям будут мотивировать использование моделей с высокой точностью (случайный лес), в то время как дорогостоящие ложноотрицательные результаты приведут к моделям, которые максимизируют отзыв (MPC или LR).

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

  • Создавайте временные характеристики: характеристики за последние n дней.
  • Функции скользящего среднего: создание оконных операций назад во времени для каждого события и меток этих окон на основе событий оттока вперед во времени.
  • Переопределите проблему как проблему регрессии, определив отток как количество дней до отмены.
  • Изучите другие модели: деревья решений, деревья с усилением и SVM.

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