Сегментация с использованием алгоритма кластеризации K-Means.
Бизнес-контекст
Предприятия всегда находятся в процессе разработки методов сегментации своих клиентов. Процесс сегментации гарантирует, что бизнес сможет разработать стратегии для конкретных потребителей и создать продукт или услугу, соответствующие их потребностям. Это НЕОБХОДИМОЕ действие перед запуском любой маркетинговой онлайн-кампании.
Сегментация клиентов — это популярное применение обучения без учителя. При этом кластеры используются компанией для определения и размещения своих клиентов в различных группах, которые классифицируются на основе региона, пола, возраста, предпочтений и т. д.
Постановка задачи
Предположим, что у нас есть организация, которая продает часть товара, и вам нужно понять, насколько хорошо выполняется продажа товара.
У вас есть данные, которые мы можем проанализировать, но какой анализ мы можем сделать? Что ж, мы можем сегментировать клиентов на основе их покупательского поведения на рынке.
Имейте в виду, что данные действительно огромны, и мы не можем проанализировать их невооруженным глазом. Для этого мы будем использовать алгоритмы машинного обучения и вычислительную мощность. Эта статья покажет вам, как группировать клиентов по сегментам на основе их поведения с помощью алгоритма K-средних в Python.
Я надеюсь, что эта статья поможет вам шаг за шагом выполнить сегментацию клиентов, начиная с подготовки данных и заканчивая их кластеризацией.
План атаки
Прежде чем мы приступим к процессу, я вкратце расскажу вам, какие шаги мы предпримем.
- Соберите данные
- Создать денежную таблицу частоты недавности (RFM)
- Управлять асимметрией и масштабировать каждую переменную
- Исследуйте данные
- Кластеризация данных
- Интерпретировать результат
Сбор данных
На этом этапе мы сначала соберем данные. В этом случае мы возьмем данные из машинного обучения UCI, называемого набором данных онлайн-розничной торговли.
Сам набор данных представляет собой данные о транзакциях, которые содержат транзакции с 1 декабря 2010 г. по 9 декабря 2011 г. для интернет-магазина в Великобритании.
Каждая строка представляет происходящую транзакцию. Он включает название продукта, количество, цену и другие столбцы, представляющие ID.
Вы можете получить доступ к набору данных здесь.
Вот размер набора данных.
(541909, 8)
В этом случае мы не используем все строки. Вместо этого мы выберем 10 000 строк из набора данных и предполагаем, что это все транзакции, которые совершают клиенты.
Код будет выглядеть так,
# Import The Libraries # ! pip install xlrd import pandas as pd import matplotlib.pyplot as plt import numpy as np # Import The Dataset df = pd.read_excel('dataset.xlsx') df = df[df['CustomerID'].notna()] # Sample the dataset df_fix = df.sample(10000, random_state = 42)
Вот проблеск набора данных,
Создайте таблицу RFM
После выборки данных мы облегчим анализ данных.
Для сегментации клиентов есть несколько показателей, которые мы можем использовать, например, когда клиент покупает продукт в последний раз, как часто клиент покупает продукт и сколько клиент платит за продукт. Мы будем называть эту сегментацию RFM-сегментацией.
Чтобы создать таблицу RFM, мы можем создать такие столбцы, как столбец «Недавность», «Частота» и «Денежная стоимость».
Чтобы получить количество дней для столбца недавности, мы можем вычесть дату моментального снимка из даты, когда произошла транзакция.
Чтобы создать столбец частоты, мы можем подсчитать количество транзакций каждого клиента.
Наконец, чтобы создать столбец денежного значения, мы можем просуммировать все транзакции для каждого клиента.
Код выглядит так,
# Convert to show date only from datetime import datetime df_fix["InvoiceDate"] = df_fix["InvoiceDate"].dt.date # Create TotalSum colummn df_fix["TotalSum"] = df_fix["Quantity"] * df_fix["UnitPrice"] # Create date variable that records recency import datetime snapshot_date = max(df_fix.InvoiceDate) + datetime.timedelta(days=1) # Aggregate data by each customer customers = df_fix.groupby(['CustomerID']).agg({ 'InvoiceDate': lambda x: (snapshot_date - x.max()).days, 'InvoiceNo': 'count', 'TotalSum': 'sum'}) # Rename columns customers.rename(columns = {'InvoiceDate': 'Recency', 'InvoiceNo': 'Frequency', 'TotalSum': 'MonetaryValue'}, inplace=True)
Вот проблеск набора данных,
Прямо сейчас набор данных состоит из столбца давности, частоты и денежного значения. Но мы пока не можем использовать набор данных, потому что нам нужно больше предварительно обработать данные.
Управление асимметрией и масштабированием
Мы должны убедиться, что данные соответствуют этим предположениям, они,
Данные должны соответствовать предположениям, когда переменные не искажены и имеют одинаковое среднее значение и дисперсию.
Из-за этого мы должны управлять асимметрией переменных.
Вот визуализации каждой переменной,
Как мы видим сверху, мы должны преобразовать данные, чтобы они имели более симметричную форму.
Есть несколько методов, которые мы можем использовать для управления асимметрией, а именно:
- преобразование журнала
- преобразование квадратного корня
- преобразование бокса-кокса
Примечание. Преобразование можно использовать тогда и только тогда, когда переменная имеет только положительные значения.
Ниже представлены визуализации каждой переменной с преобразованиями и без них. Сверху слева по часовой стрелке для каждой переменной показан график без преобразования, логарифмического преобразования, преобразования квадратного корня и преобразования бокс-кокса.
На основе этой визуализации видно, что переменные с преобразованием бокса-кокса имеют более симметричную форму, чем другие преобразования.
Чтобы убедиться, мы вычисляем каждую переменную с помощью функции перекоса. Результат выглядит так,
variable, without, log, sqrt, box-cox transformations Recency, 14.77, 0.85, 3.67, 0.16 Frequency, 0.93, -0.72, 0.32, -0.1
Вот как интерпретировать значение асимметрии. Если значение близко к 0, переменная имеет тенденцию иметь симметричную форму. Однако, если это не так, переменная имеет перекос. На основе этого расчета мы используем переменные, использующие преобразования бокса-кокса.
На основе этого расчета мы будем использовать переменные, использующие преобразования бокса-кокса. За исключением переменной Денежное значение, поскольку эта переменная содержит отрицательные значения. Чтобы обработать эту переменную, мы можем использовать преобразование кубического корня к данным, поэтому сравнение выглядит следующим образом:
Используя преобразование, мы получим менее искаженные данные. Значение асимметрии снижается с 16,63 до 1,16. Следовательно, мы можем преобразовать таблицу RFM с помощью этого кода,
from scipy import stats customers_fix = pd.DataFrame() customers_fix["Recency"] = stats.boxcox(customers['Recency'])[0] customers_fix["Frequency"] = stats.boxcox(customers['Frequency'])[0] customers_fix["MonetaryValue"] = pd.Series(np.cbrt(customers['MonetaryValue'])).values customers_fix.tail()
Это будет выглядеть так,
Можем ли мы использовать данные прямо сейчас? Еще нет. Если мы еще раз посмотрим на график, то увидим, что каждая переменная не имеет одинакового среднего значения и дисперсии. Мы должны нормализовать его. Для нормализации мы можем использовать объект StandardScaler из библиотеки scikit-learn. Код будет выглядеть так,
# Import library from sklearn.preprocessing import StandardScaler # Initialize the Object scaler = StandardScaler() # Fit and Transform The Data scaler.fit(customers_fix) customers_normalized = scaler.transform(customers_fix) # Assert that it has mean 0 and variance 1 print(customers_normalized.mean(axis = 0).round(2)) # [0. -0. 0.] print(customers_normalized.std(axis = 0).round(2)) # [1. 1. 1.]
Данные будут выглядеть так,
Наконец, мы можем выполнить кластеризацию, используя эти данные.
Решение разработано
Моделирование
Сразу после предварительной обработки данных мы можем сосредоточиться на моделировании. Чтобы сделать сегментацию данных, мы можем использовать алгоритм K-Means.
Алгоритм K-средних — это алгоритм обучения без учителя, который использует геометрический принцип для определения того, какой кластер принадлежит данным. Определив каждый центроид, мы вычисляем расстояние до каждого центроида. Каждые данные принадлежат центроиду, если он имеет наименьшее расстояние от другого. Это повторяется до тех пор, пока следующая сумма расстояния не будет иметь значительных изменений, чем раньше.
Реализовать K-Means в Python очень просто. Для этого мы можем использовать функцию KMeans из scikit-learn.
Чтобы наша кластеризация достигла максимальной производительности, мы должны определить, какой гиперпараметр соответствует данным. Чтобы определить, какой гиперпараметр лучше всего подходит для нашей модели и данных, мы можем использовать метод локтя. Код будет выглядеть так,
from sklearn.cluster import KMeans sse = {} for k in range(1, 11): kmeans = KMeans(n_clusters=k, random_state=42) kmeans.fit(customers_normalized) sse[k] = kmeans.inertia_ # SSE to closest cluster centroidplt.title('The Elbow Method') plt.xlabel('k') plt.ylabel('SSE') sns.pointplot(x=list(sse.keys()), y=list(sse.values())) plt.show()
Вот результат,
Как трактовать сюжет? Ось x — это значение k, а ось y — значение SSE данных. Мы выберем лучший параметр, посмотрев, где значение k будет иметь линейный тренд для следующего последовательного k.
Улучшения решения
Основываясь на наших наблюдениях, значение k, равное 3, является лучшим гиперпараметром для нашей модели, потому что следующее значение k имеет линейный тренд. Поэтому нашей лучшей моделью для данных является K-Means с числом кластеров 3.
Теперь мы можем подогнать модель под этот код,
model = KMeans(n_clusters=3, random_state=42) model.fit(customers_normalized) model.labels_.shape
Подбирая модель, мы можем иметь кластеры, которым принадлежат все данные. Таким образом, мы можем анализировать данные.
Интерпретировать сегмент
Мы можем обобщить таблицу RFM на основе кластеров и вычислить среднее значение каждой переменной. Код будет выглядеть так,
customers["Cluster"] = model.labels_ customers.groupby('Cluster').agg({ 'Recency':'mean', 'Frequency':'mean', 'MonetaryValue':['mean', 'count']}).round(2)
Вывод из кода выглядит так,
Кроме того, мы можем анализировать сегменты с помощью snake plot. Для этого требуется нормализованный набор данных, а также метки кластера. Используя этот график, мы можем получить хорошую визуализацию данных о том, чем кластер отличается друг от друга. Мы можем сделать сюжет, используя этот код,
# Create the dataframe df_normalized = pd.DataFrame(customers_normalized, columns=['Recency', 'Frequency', 'MonetaryValue']) df_normalized['ID'] = customers.index df_normalized['Cluster'] = model.labels_ # Melt The Data df_nor_melt = pd.melt(df_normalized.reset_index(), id_vars=['ID', 'Cluster'], value_vars=['Recency','Frequency','MonetaryValue'], var_name='Attribute', value_name='Value') df_nor_melt.head() # Visualize it sns.lineplot('Attribute', 'Value', hue='Cluster', data=df_nor_melt)
И вот результат,
Используя этот график, мы знаем, чем отличается каждый сегмент. Он описывает больше, чем мы используем сводную таблицу.
Мы делаем вывод, что кластер 0 встречается часто, тратит больше и покупают товар недавно. Следовательно, это может быть группа постоянных клиентов.
Затем кластер 1 реже, меньше тратит, но покупают товар недавно. Следовательно, это может быть группа новых клиентов.
Наконец, группа 2 реже, меньше тратит, и они покупают продукт в старое время. Следовательно, это может быть группа ушедших клиентов.
Заключение
В заключение, сегментация клиентов действительно необходима для того, чтобы знать, какие характеристики существуют у каждого клиента. В статье показано, как реализовать это с помощью Python. Надеюсь, что эта статья будет вам полезна, и вы сможете реализовать ее на своем деле.
Ссылка на рабочий проект
Если вы хотите увидеть, как выглядит код, вы можете проверить этот Google Colab здесь.
Рекомендации
[1] Дацин К., Сай Л.С. и Кун Г. Интеллектуальный анализ данных для индустрии онлайн-торговли: пример сегментации клиентов на основе модели RFM с использованием интеллектуального анализа данных (2012 г.), Journal of Database Marketing и Управление стратегией работы с клиентами.
[2] Миллман К. Дж., Айвазис М. Python для ученых и инженеров (2011 г.), Computing in Science & Engineering.
[3] Радечич Д. Top 3 Methods for Handing Skewed Data (2020), Towards Data Science.
[4] Метод локтя для оптимального значения k в KMeans, Компьютерщики для компьютерщиков.