Сегментация клиентов в Python Практический подход
Python в действии Практический подход к сегментации клиентов
Сегментация клиентов может помочь бизнесам настраивать свои маркетинговые усилия и повышать удовлетворенность клиентов. Вот как.
Функционально, сегментация клиентов предполагает разделение клиентской базы на отдельные группы или сегменты на основе общих характеристик и поведения. Понимая потребности и предпочтения каждого сегмента, бизнесы могут предоставлять более персонализированные и эффективные маркетинговые кампании, что приводит к увеличению удержания клиентов и доходу.
В этом учебнике мы исследуем сегментацию клиентов с использованием Python, комбинируя две основные техники: RFM анализ (Recency, Frequency, Monetary) и K-Means кластеризацию. RFM анализ предоставляет структурированный фреймворк для оценки поведения клиентов, а K-Means кластеризация предлагает основанный на данных подход к группировке клиентов в значимые сегменты. Мы будем работать с реальными данными из розничной отрасли: набор данных Online Retail из репозитория машинного обучения UCI.
- Понимание метрик классификации Ваш руководитель по оценке точности модели
- Парадигмальный переход в разработке программного обеспечения искусственный интеллект AI-агентов GPTConsole открывает новые горизонты
- «Docker представляет ‘Docker AI’ революционное изменение для производительности разработчиков с помощью контекстно-ориентированной автоматизации»
От предварительной обработки данных до анализа и визуализации кластеров, мы будем писать код на каждом шаге. Итак, приступим!
Наш подход: RFM анализ и K-Means кластеризация
Давайте начнем с постановки цели: применяя RFM анализ и K-Means кластеризацию к этому набору данных, мы хотим получить инсайты в поведение и предпочтения клиентов.
RFM анализ – это простой, но мощный метод для количественной оценки поведения клиентов. Он оценивает клиентов на основе трех ключевых измерений:
- Recency (R): Как недавно конкретный клиент совершил покупку?
- Frequency (F): Как часто они совершают покупки?
- Monetary Value (M): Сколько денег они тратят?
Мы используем информацию в наборе данных для вычисления значений для R, F и M. Затем мы сопоставим эти значения с общепринятой шкалой оценок RFM от 1 до 5.
Если вы хотите, вы можете дополнительно исследовать и анализировать с использованием этих оценок RFM. Но мы попытаемся выявить сегменты клиентов с похожими RFM характеристиками. И для этого мы используем K-Means кластеризацию, алгоритм машинного обучения без учителя, который группирует похожие точки данных в кластеры.
Итак, приступим к написанию кода!
🔗 Ссылка на блокнот Google Colab.
Шаг 1 – Импорт необходимых библиотек и модулей
Сначала давайте импортируем необходимые библиотеки и конкретные модули по мере необходимости:
import pandas as pdimport matplotlib.pyplot as pltfrom sklearn.cluster import KMeans
Нам понадобятся pandas и matplotlib для исследования и визуализации данных, а класс KMeans
из модуля cluster scikit-learn для выполнения K-Means кластеризации.
Шаг 2 – Загрузка набора данных
Как упоминалось ранее, мы будем использовать набор данных Online Retail. Набор данных содержит записи о клиентах: транзакционную информацию, включая даты покупок, количество, цены и идентификаторы клиентов.
Давайте считаем данные из оригинального файла Excel по его URL в pandas dataframe.
# Загрузка набора данных из репозитория UCIurl = "https://archive.ics.uci.edu/ml/machine-learning-databases/00352/Online%20Retail.xlsx"data = pd.read_excel(url)
В качестве альтернативы вы можете скачать набор данных и считать файл Excel в pandas dataframe.
Шаг 3 – Исследование и очистка набора данных
Теперь давайте начнем изучать набор данных. Посмотрите на первые несколько строк набора данных:
data.head()
Теперь вызовите метод describe()
для фрейма данных, чтобы лучше понять числовые признаки:
data.describe()
Мы видим, что столбец «CustomerID» в настоящее время представляет собой значение с плавающей запятой. При очистке данных мы приведем его к целому числу:
Также обратите внимание, что набор данных довольно шумный. Столбцы «Quantity» и «UnitPrice» содержат отрицательные значения:
Давайте подробнее рассмотрим столбцы и их типы данных:
data.info()
Мы видим, что в наборе данных более 541 тыс. записей, а столбцы «Description» и «CustomerID» содержат пропущенные значения: Давайте получим количество пропущенных значений в каждом столбце:
# Проверяем наличие пропущенных значений в каждом столбце missing_values = data.isnull().sum()print(missing_values)
Как и ожидалось, столбцы «CustomerID» и «Description» содержат пропущенные значения:
Для нашего анализа нам не нужно описание продукта, содержащееся в столбце «Description». Однако нам нужен «CustomerID» для следующих шагов в нашем анализе. Поэтому давайте удалим записи с отсутствующим «CustomerID»:
# Удалить строки с отсутствующими CustomerIDdata.dropna(subset=['CustomerID'], inplace=True)
Также вспомним, что значения столбцов «Quantity» и «UnitPrice» должны быть строго неотрицательными. Но они содержат отрицательные значения. Так что давайте также удалим записи с отрицательными значениями для «Quantity» и «UnitPrice»:
# Удалить строки с отрицательными Quantity и Pricedata = data[(data['Quantity'] > 0) & (data['UnitPrice'] > 0)]
Также преобразуем «CustomerID» в целое число:
data['CustomerID'] = data['CustomerID'].astype(int)# Проверка преобразования типа данныхprint(data.dtypes)
Шаг 4 – Рассчет Recency, Frequency и Monetary Value
Начнем с определения сравнительной даты snapshot_date
, которая находится на день позже наиболее поздней даты в столбце «InvoiceDate»:
snapshot_date = max(data['InvoiceDate']) + pd.DateOffset(days=1)
Затем создайте столбец «Total», который содержит Quantity * UnitPrice для всех записей:
data['Total'] = data['Quantity'] * data['UnitPrice']
Для расчета Recency, Frequency и MonetaryValue мы вычисляем следующее – сгруппированное по CustomerID:
- Для Recency мы вычисляем разницу между самой последней датой покупки и сравнительной датой (
snapshot_date
). Это дает количество дней с момента последней покупки клиента. Таким образом, меньшие значения указывают на то, что клиент недавно совершил покупку. Но когда речь идет о значениях Recency, мы бы хотели, чтобы клиенты, которые недавно покупали, имели более высокий балл Recency, верно? Мы справимся с этим на следующем шаге. - Поскольку Frequency показывает, насколько часто клиент совершает покупки, мы вычислим его как общее количество уникальных счетов или транзакций, совершенных каждым клиентом.
- Monetary value количественно представляет сумму денег, которую клиент тратит. Поэтому мы найдем среднее значение общей денежной стоимости по транзакциям.
rfm = data.groupby('CustomerID').agg({ 'InvoiceDate': lambda x: (snapshot_date - x.max()).days, 'InvoiceNo': 'nunique', 'Total': 'sum'})
Давайте переименуем столбцы для удобочитаемости:
rfm.rename(columns={'InvoiceDate': 'Recency', 'InvoiceNo': 'Frequency', 'Total': 'MonetaryValue'}, inplace=True)rfm.head()
Шаг 5 – Отобразить значения RFM на шкалу от 1 до 5
Теперь давайте отобразим значения столбцов “Recency”, “Frequency” и “MonetaryValue” на шкалу от 1 до 5; одно из {1,2,3,4,5}.
Суть в том, чтобы присвоить значения пяти разным группам и отобразить каждую группу на значение. Для определения границ групп давайте воспользуемся квантильными значениями столбцов “Recency”, “Frequency” и “MonetaryValue”:
rfm.describe()
Вот как мы определяем границы групп:
# Рассчитываем пользовательские границы групп для оценок Recency, Frequency и Monetary scoresrecency_bins = [rfm['Recency'].min()-1, 20, 50, 150, 250, rfm['Recency'].max()]frequency_bins = [rfm['Frequency'].min() - 1, 2, 3, 10, 100, rfm['Frequency'].max()]monetary_bins = [rfm['MonetaryValue'].min() - 3, 300, 600, 2000, 5000, rfm['MonetaryValue'].max()]
Теперь, когда мы определили границы групп, давайте отобразим оценки соответствующим меткам в диапазоне от 1 до 5 (включительно):
# Рассчитываем оценку Recency на основе пользовательских границ rfm['R_Score'] = pd.cut(rfm['Recency'], bins=recency_bins, labels=range(1, 6), include_lowest=True)# Реверсируем оценки Recency, чтобы более высокие значения указывали на более недавние покупкиrfm['R_Score'] = 5 - rfm['R_Score'].astype(int) + 1# Рассчитываем оценки Frequency и Monetary на основе пользовательских границrfm['F_Score'] = pd.cut(rfm['Frequency'], bins=frequency_bins, labels=range(1, 6), include_lowest=True).astype(int)rfm['M_Score'] = pd.cut(rfm['MonetaryValue'], bins=monetary_bins, labels=range(1, 6), include_lowest=True).astype(int)
Обратите внимание, что R_Score на основе групп равен 1 для недавних покупок и 5 для всех покупок, сделанных более 250 дней назад. Но мы хотим, чтобы самые недавние покупки имели R_Score равный 5, а покупки, сделанные более 250 дней назад, имели R_Score равный 1.
Чтобы получить желаемое отображение, мы делаем: 5 - rfm['R_Score'].astype(int) + 1
.
Давайте посмотрим на первые несколько строк столбцов R_Score, F_Score и M_Score:
# Выводим первые несколько строк DataFrame RFM для проверки оценокprint(rfm[['R_Score', 'F_Score', 'M_Score']].head(10))
При желании вы можете использовать эти оценки R, F и M для проведения глубокого анализа или использовать кластеризацию для выявления сегментов с похожими характеристиками RFM. Мы выберем последнее!
Шаг 6 – Выполнение кластеризации методом K-средних
Кластеризация K-Means чувствительна к масштабу признаков. Поскольку значения R, F и M находятся на одном масштабе, мы можем продолжать выполнять кластеризацию без дальнейшего масштабирования признаков.
Давайте извлечем оценки R, F и M для выполнения кластеризации K-Means:
# Извлечь оценки RFM для кластеризации K-meansX = rfm[['R_Score', 'F_Score', 'M_Score']]
Затем нам нужно найти оптимальное количество кластеров. Для этого давайте запустим алгоритм K-Means для ряда значений K и используем метод elbow, чтобы выбрать оптимальный К:
# Рассчитать инерцию (сумму квадратов расстояний) для разных значений kinertia = []for k in range(2, 11): kmeans = KMeans(n_clusters=k, n_init=10, random_state=42) kmeans.fit(X) inertia.append(kmeans.inertia_)# Построить график elbow кривойplt.figure(figsize=(8, 6), dpi=150)plt.plot(range(2, 11), inertia, marker='o')plt.xlabel('Количество кластеров (k)')plt.ylabel('Инерция')plt.title('График elbow для кластеризации K-Means')plt.grid(True)plt.show()
Мы видим, что кривая сгибается при 4 кластерах. Итак, давайте разделим базу клиентов на четыре сегмента.
Мы установили K равным 4. Итак, давайте запустим алгоритм K-Means, чтобы получить назначения кластеров для всех точек в наборе данных:
# Выполнить кластеризацию K-means с лучшим Kbest_kmeans = KMeans(n_clusters=4, n_init=10, random_state=42)rfm['Cluster'] = best_kmeans.fit_predict(X)
Шаг 7 – Интерпретация кластеров для выявления сегментов клиентов
Теперь, когда у нас есть кластеры, давайте попытаемся их характеризовать на основе оценок RFM.
# Сгруппировать по кластеру и рассчитать средние значенияcluster_summary = rfm.groupby('Cluster').agg({ 'R_Score': 'mean', 'F_Score': 'mean', 'M_Score': 'mean'}).reset_index()
Средние значения оценок R, F и M для каждого кластера уже должны дать вам представление о характеристиках.
print(cluster_summary)
Но давайте визуализируем средние значения оценок R, F и M для кластеров, чтобы было легче интерпретировать:
colors = ['#3498db', '#2ecc71', '#f39c12','#C9B1BD']# Построить среднюю оценку RFM для каждого кластерапр_figure(figsize=(10, 8),dpi=150)# Построить среднюю оценку Recencyplt.subplot(3, 1, 1)bars = plt.bar(cluster_summary.index, cluster_summary['R_Score'], color=colors)plt.xlabel('Кластер')plt.ylabel('Средний Recency')plt.title('Средний Recency для каждого кластера')plt.grid(True, linestyle='--', alpha=0.5)plt.legend(bars, cluster_summary.index, title='Кластеры')# Построить среднюю оценку Frequencyplt.subplot(3, 1, 2)bars = plt.bar(cluster_summary.index, cluster_summary['F_Score'], color=colors)plt.xlabel('Кластер')plt.ylabel('Средняя Frequency')plt.title('Средняя Frequency для каждого кластера')plt.grid(True, linestyle='--', alpha=0.5)plt.legend(bars, cluster_summary.index, title='Кластеры')# Построить среднюю оценку Monetaryplt.subplot(3, 1, 3)bars = plt.bar(cluster_summary.index, cluster_summary['M_Score'], color=colors)plt.xlabel('Кластер')plt.ylabel('Средний Monetary')plt.title('Средняя денежная единица для каждого кластера')plt.grid(True, linestyle='--', alpha=0.5)plt.legend(bars, cluster_summary.index, title='Кластеры')plt.tight_layout()plt.show()
Заметьте, как клиенты в каждом из сегментов могут быть характеризованы на основе значений актуальности, частоты и денежных стоимостей:
- Кластер 0: Из всех четырех кластеров, этот кластер имеет наивысшую актуальность, частоту и денежные значения. Давайте назовем клиентов в этом кластере чемпионами (или сильными покупателями).
- Кластер 1: Этот кластер характеризуется умеренной актуальностью, частотой и денежными значениями. Эти клиенты все еще тратят больше и покупают чаще, чем кластеры 2 и 3. Давайте назовем их лояльными клиентами.
- Кластер 2: Клиенты в этом кластере обычно тратят меньше. Они не часто покупают и также не совершали покупок в последнее время. Скорее всего, это неактивные или находящиеся в риске клиенты.
- Кластер 3: Этот кластер характеризуется высокой актуальностью, относительно нижней частотой и умеренными денежными значениями. Таким образом, это недавние клиенты, которые могут стать долгосрочными клиентами.
Вот несколько примеров того, как вы можете настроить маркетинговые усилия, чтобы привлечь клиентов из каждого сегмента и повысить вовлеченность и удержание клиентов:
- Для Чемпионов/Сильных покупателей: Предлагайте персонализированные специальные скидки, привилегии доступа и другие премиальные льготы, чтобы они чувствовали себя ценными и оцененными.
- Для Лояльных клиентов: Кампании по оценке, бонусы за рекомендацию и вознаграждения за лояльность.
- Для Клиентов, находящихся в риске: Усилия по повторному привлечению, включающие скидки или акции, чтобы стимулировать покупки.
- Для Недавних клиентов: Целевые кампании, позволяющие им узнать о бренде и предоставляющие скидки на последующие покупки.
Также полезно понимать, какой процент клиентов находится в различных сегментах. Это дополнительно поможет оптимизировать маркетинговые усилия и развивать ваш бизнес.
Давайте визуализируем распределение различных кластеров с помощью круговой диаграммы:
cluster_counts = rfm['Cluster'].value_counts()colors = ['#3498db', '#2ecc71', '#f39c12','#C9B1BD']# Вычислить общее количество клиентовtotal_customers = cluster_counts.sum()# Вычислить процент клиентов в каждом кластереpercentage_customers = (cluster_counts / total_customers) * 100labels = ['Чемпионы (сильные покупатели)','Лояльные клиенты','Клиенты, находящиеся в риске','Недавние клиенты']# Создать круговую диаграммуplt.figure(figsize=(8, 8),dpi=200)plt.pie(percentage_customers, labels=labels, autopct='%1.1f%%', startangle=90, colors=colors)plt.title('Процент клиентов в каждом кластере')plt.legend(cluster_summary['Cluster'], title='Кластер', loc='upper left')plt.show()
Вот и все! В этом примере у нас достаточно равномерное распределение клиентов по сегментам. Поэтому мы можем инвестировать время и усилия в удержание существующих клиентов, повторное привлечение клиентов, находящихся в риске, и обучение недавних клиентов.
Сводка
И это все! Мы прошли путь от более чем 154 тыс. записей о клиентах к 4 кластерам за 7 простых шагов. Я надеюсь, вы понимаете, как клиентская сегментация позволяет принимать решения, основанные на данных, которые влияют на рост бизнеса и удовлетворенность клиентов, обеспечивая:
- Персонализацию: Сегментация позволяет бизнесам адаптировать свои маркетинговые сообщения, рекомендации по продуктам и акции под специфические потребности и интересы каждой группы клиентов.
- Улучшенную Таргетированность: Определение клиентов высокой ценности и находящихся в риске позволяет бизнесам эффективнее распределять ресурсы, сосредотачивая усилия там, где они наиболее вероятно принесут результаты.
- Удержание Клиентов: Сегментация помогает бизнесам создавать стратегии удержания, понимая то, что удерживает клиентов и делает их довольными.
В качестве следующего шага попробуйте применить этот подход к другому набору данных, задокументируйте свой путь и поделитесь с сообществом! Но помните, что эффективная сегментация клиентов и организация целевых кампаний требует хорошего понимания вашей клиентской базы и ее эволюции. Поэтому требуется периодический анализ для усовершенствования стратегий со временем.
Благодарность за набор данных
Датасет Онлайн Розница распространяется на условиях лицензии Creative Commons Attribution 4.0 International (CC BY 4.0):
Онлайн-розница. (2015). Репозиторий машинного обучения UCI. https://doi.org/10.24432/C5BW33. Bala Priya C – разработчик и технический писатель из Индии. Ей нравится работать в пересечении математики, программирования, науки о данных и создания контента. Ее областями интереса и экспертизы являются DevOps, наука о данных и обработка естественного языка. Она любит чтение, письмо, кодирование и кофе! В настоящее время она работает над изучением и обменом своими знаниями с сообществом разработчиков, создавая учебники, руководства, мнения и многое другое.
[Bala Priya C](https://twitter.com/balawc27) – разработчик и технический писатель из Индии. Ей нравится работать в пересечении математики, программирования, науки о данных и создания контента. Ее областями интереса и экспертизы являются DevOps, наука о данных и обработка естественного языка. Она любит чтение, письмо, кодирование и кофе! В настоящее время она работает над изучением и обменом своими знаниями с сообществом разработчиков, создавая учебники, руководства, мнения и многое другое.