Проект прогнозирования оттока клиентов с помощью PySpark

Обзор

Проект является частью Capstone Project Udacity Data Scientist Nanodegree. Прогнозирование оттока клиентов - одна из наиболее распространенных бизнес-проблем. Это важная часть роли специалиста по анализу данных в бизнесе и создании продукта. Этот проект относится к сфере музыкальной индустрии, и одна из важнейших составляющих современного потокового мира - удерживать клиентов на связи с бизнесом, предотвращая отток.

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

Данные проекта Capstone предоставлены Udacity. Размер данных составляет 248 МБ, что является подмножеством исходных данных, составляющих 12 ГБ. Данные содержат информацию о каждой записи сеанса, сделанной пользователем в Sparkify, а также содержат основную интересующую переменную - отменил ли пользователь свою подписку или нет.

Таким образом, ради этого проекта, с намерением масштабировать его до всего набора данных 12 ГБ, это проект прогнозирования оттока клиентов с использованием API Python Apache Spark, pyspark.

Проблема

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

В модели используется помеченная целевая функция под названием Churn,, которая принимает значение 1, если клиент ушел. Бинарная природа проблемы решается с помощью алгоритма классификации с использованием pyspark.ml - библиотеки машинного обучения Pyspark.

Проект включал (в общих чертах) следующие шаги:

  • Загрузка и очистка данных
  • Исследовательский анализ данных - содержит визуализацию данных и исследования с использованием статистики.
  • Разработка функций - на основе EDA следующим шагом является разработка функций для прогнозирования целевой переменной - Churn
  • Моделирование - это раздел, в котором используются различные алгоритмы классификации и сравниваются их на основе оценочной метрики F1-Score (подробнее о метрике, выбранной ниже). Этот шаг также включает настройку модели, при которой выбранные модели используются для поиска по сетке, чтобы оптимизировать выбор модели.
  • Размышления и возможные улучшения - что можно улучшить и каковы ограничения?

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

Данные

Данные предоставляются Udacity, их длина составляет примерно 544 000 строк, а размер - 248 МБ. Я использовал Watson Studio из IBM Cloud для загрузки данных и работы над Jupyter Notebook с включенными Python 3.7 и Spark 3.0.

Общая описательная статистика о данных:

Данные не содержат значений NaN. Однако данные user_id в DataFrame действительно содержат пустые значения.

По сути, вместо NaN DataFrame содержит пустые значения для пользователей, которые очищаются.

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

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

Большинство пользователей из 4 регионов США.

Как видно на графике выше, большинство пользователей прибывают из Калифорнии, Техаса, кластера Нью-Йорка / Нью-Джерси / Пенсильвании, Флориды, Иллинойса и т. Д. - в основном там, где самая высокая плотность населения и большие города.

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

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

Количество бесплатных пользователей составляет 370, а пользователей, использующих платную версию, - 321. Общее количество уникальных пользователей составляет 448, поэтому количество пользователей, которые изменились, составляет (370 + 321) - 448 = 243 пользователя, которые изменили свой уровень.

Характеристики gender, auth, length, level, location, page, song, ts, userAgent исследуются далее, с разбивкой по категориям и анализирующим поведение оттока на основе этих разделений по категориям. Более подробная информация об EDA представлена ​​в следующем разделе.

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

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

Целевая переменная Churn берется, как предлагает Udacity, из события с именем Cancellation Confirmation из переменной page. Пометка этого события и создание фиктивной переменной, принимающей 1, если пользователь отменил или нет, - вот как получается целевая переменная.

flag_event = udf(lambda x: 1 if x == 'Cancellation Confirmation' else 0, IntegerType())
df_new_churn = df_new.withColumn('Churned', flag_event('page'))
df_new_churn.dropDuplicates(['userId']).select('Churn').groupby('Churn').count().collect()

udf - это функция, определяемая пользователем, импортированная из pyspark.sql.functions.

  • Поведение оттока в среднем по времени

  • Час дня - когда пользователи, уходящие за день, наиболее активны?

  • Дни в месяце - когда в месяце пользователи были наиболее активными?

  • Какой браузер и платформы чаще всего используются пользователем?

  • Изменение активности по наиболее посещаемым страницам.

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

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

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

В библиотеке машинного обучения Spark есть класс конструирования объектов VectorAssembler для преобразования столбцов признаков в плотный вектор.

vector = VectorAssembler(inputCols=num_features, outputCol='numerical_features')
# This code uses the VectorAssembler to convert the multiple 
# numerical columns into a Dense Vector

Категориальные переменные

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

  • Пол - метка, кодирующая пол, делая 0 и 1 для двух уникальных значений, соответствующим образом идентифицируя пользователя.
  • Уровень - Аналогично, для двух разных уровней переменные кодируются метками.
  • браузер - 4 различных используемых браузера имеют кодировку от 0 до 3.
  • платформа - различные платформы, используемые пользователями для просмотра Sparkify, закодированы на этикетках.

Числовые переменные

  • Длина - берется средняя длина, стандартное отклонение средней длины, минимальное и максимальное значения длины для каждого пользователя.
  • Страница - в зависимости от активности пользователей на разных страницах выбираются наиболее посещаемые страницы, агрегированные по количеству.
  • Всего песен - Общее количество песен, прослушанных каждым пользователем, принимается в качестве другой числовой переменной.
  • Уникальные песни - общее количество уникальных песен каждого пользователя. Эта переменная показывает разнообразие песен, которые слушает пользователь.
  • Уникальные исполнители - Уникальное количество исполнителей, которых слушает каждый пользователь.
  • Процент операций до 15 числа месяца. Обратите внимание на то, как пользователи, которые ушли, совершили много операций в первой половине месяца.
  • Процент операций после 12 часов дня. Как и в случае с переменной выше, как текущие, так и оставшиеся пользователи имеют высокий всплеск активности во второй половине дня.
  • Целевая переменная будет «Churn».

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

Для задачи классификации выбрано 4 алгоритма - RandomForestClassifier, GBTClassifier, LogisticRegression и LinearSVM. Метрика, выбранная для оценки моделей, - это F1-Score. F1-Score учитывает ложные срабатывания и ложные отрицательные результаты в своих расчетах, в отличие от показателя точности, который учитывает только истинные положительные и истинные отрицательные результаты. Из-за несбалансированного характера целевой переменной F1-Score дает более объективный результат.

F1-Score

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

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

Данные разделены на набор для обучения и проверки. Набор для проверки имеет размер 15% от всех данных.

Настройка гиперпараметров

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

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

Здесь настраиваются параметры maxIter и regParam.

  • maxIter - максимальное количество запусков алгоритма для оптимизации функции потерь.
  • regParam - параметр регуляризации. По умолчанию для elasticNetParam установлено значение 0,0, что означает, что положительный параметр regParam и 0 elasticNetParam является регрессией гребня. Эти дополнительные штрафы добавляются для контроля таких аспектов, как мультиколлинеарность.
  • Диапазон maxIter в сетке для настройки равен [50, 100], а для regParam - [0.0, 0.01, 0.001].

Перекрестный валидатор с поиском по сетке дал F1-Score 80,77%, что является небольшим улучшением по сравнению с исходной моделью. Наложение дополнительных штрафов дало лучший результат. Хотя есть некоторые недостатки логистической регрессии, которых следует опасаться, которые подробно описаны в блокноте Python этого проекта на Github.

2. Линейный SVM

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

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

  • Возможно, используя другие гиперпараметры, мы сможем улучшить показатель f1 и точность.
  • Тем не менее, с большим количеством данных и сбалансированным набором данных я лично считаю, что Linear SVM будет работать лучше.
  • Диапазон maxIter в сетке для настройки равен [50, 100, 150], а regParam - [0.0, 0.01].

3. Классификатор случайных лесов

Здесь настраиваются параметры maxDepth и numTrees.

  • maxDepth - глубина каждого дерева решений в ансамбле. Теоретически, чем глубже деревья, тем больше информации собирается для классификации, но это также может привести к переобучению. Мы увидим, почему это не имеет значения.
  • numTrees - это общее количество деревьев решений для запуска в ансамбле с последующим усреднением. По умолчанию значение равно 20, и чем меньше деревья, тем больше размер выборки, необходимый для запуска каждого дерева решений.
  • Значения параметра maxDepth, заданные в сетке для настройки, равны [5, 10], а диапазон numTrees - [10, 20].

Настройка гиперпараметров для классификатора случайного леса не улучшила модель по сравнению с исходной моделью.

  • Тем не менее, 88,5% F1-Score - неплохой результат, и поэтому, с точки зрения масштабирования алгоритма на более крупный набор данных 12 ГБ, я бы порекомендовал классификатор ансамбля случайного леса, с некоторыми мыслями в голове. Эти мысли упоминаются в разделе «Размышления и улучшения» ниже.

Сводка результатов по моделям для поиска по сетке

Заключительные замечания

Размышления

  • Классификатор случайного леса дает наивысший F1-балл примерно 88,5%, и, таким образом, говоря о масштабируемости этого анализа до полного набора данных 12 ГБ, следует рассмотреть возможность использования классификатора случайного леса. F1-Score является более разумной метрикой для рассмотрения, поскольку точность не полностью учитывает несбалансированный характер целевой переменной (отток).
  • Другие модели, такие как алгоритмы линейного SVC и логистической регрессии, также работают хорошо, но не так хорошо, как случайный лес.
  • Один из наиболее важных аспектов этого проекта, которого не хватает, - это возможное расслоение наборов для обучения и проверки. Стратификация по-прежнему приводит к несбалансированному набору данных, который затем будет разделен на две части в соответствии с заданными пропорциями, но это лучше, чем случайное разделение.

Улучшения

  • Размер набора данных и проводимый анализ ограничиваются количеством уникальных пользователей в наборе данных. Следовательно, будучи уже небольшим, несбалансированный характер набора данных может привести к завышению показателей, например к высокому баллу F1. Если бы целевая переменная была сбалансированной, показатели, безусловно, были бы ниже, но могут быть или не быть достаточно низкими, чтобы сделать этот анализ недействительным.
  • Одно из возможных решений - недостаточная выборка. Недостаточная выборка класса большинства (отток = 0), чтобы сделать его равным классу меньшинства (отток = 1), приведет к более объективным оценкам показателей, таких как F1-Score и Accuracy. Однако есть недостатки. Недостаточная выборка значительно уменьшает размер набора данных, и данных может не хватить для обучения с использованием предложенных моделей. Хотя это можно рассматривать, это все же риск, если взять такой небольшой набор данных. Применение недостаточной выборки к набору данных размером 12 ГБ может иметь или не иметь этих последствий, но, безусловно, будет беспристрастным.
  • Другое решение - применение подобной SMOTE техники для избыточной выборки класса меньшинства до размера класса большинства. Это имеет такое же значение, что и недостаточная выборка, но в другом направлении. Передискретизация по существу создает синтетические копии существующих точек данных и, таким образом, может привести к переобучению.

Большое спасибо Udacity за прекрасный опыт обучения, которым, безусловно, был этот проект Capstone! :)

Посетите этот проект на Github here! И хлопайте мне в ладоши, если он вам нравится! знак равно

Ссылки

Kaggle

"Переполнение стека"

Документация Spark ML

Ученый Udacity Data Nanodegree