Ссылка на блокнот и git-репозиторий этого проекта.

В прошлом посте мы получили следующие кластеры для клиентов нашей компании:

При кластеризации клиентов с помощью алгоритма K-средних было ясно, что большинство клиентов не были хорошо представлены тремя функциями, созданными при разработке функций, поскольку более 99% из них были помечены в одном кластере. Итак, в этом новом цикле CRISP я работал над проектированием признаков и подготовкой данных, масштабированием признаков с помощью min-max Scaler.

Масштабирование само по себе может значительно улучшить возможности моделей, таких как K-means, кластеризовать наших клиентов. Причина этого в том, что эти модели используют евклидово расстояние в качестве основы для расстояния между записями в данных. Кроме того, учитывая, что несвязанные шкалы, такие как валовой доход (доллары в год) и давность (дни с момента последней покупки), связаны в одном и том же анализе, интерпретируемость значений не важна при группировании разных точек. Например, если бы нашими переменными были широта и долгота, это было бы не так, и подготовка данных была бы не только ненужной, но и вредной для кластерного анализа.

Кроме того, в этом новом цикле мы собираемся применить уменьшение размерности двумя методами: UMAP и t-SNE. Использование анализа основных компонентов также распространено, но в этом наборе данных бесполезно, как мы увидим ниже.

EDA и подготовка данных

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

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

# feature selection
cols_selected = ['gross_revenue', 'recency_days', 'qtde_invoices',
                 'qtde_items', 'qtde_products', 'qtde_returns']
df43 = df4[cols_selected].copy()# preprocessing
mm = pp.MinMaxScaler()df43['gross_revenue'] = mm.fit_transform(df43[['gross_revenue']])
df43['recency_days'] = mm.fit_transform(df43[['recency_days']])
df43['qtde_invoices'] = mm.fit_transform(df43[['qtde_invoices']])
df43['qtde_items'] = mm.fit_transform(df43[['qtde_items']])
df43['qtde_products'] = mm.fit_transform(df43[['qtde_products']])
df43['qtde_returns'] = mm.fit_transform(df43[['qtde_returns']])# new dataframe
X = df43.copy()

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

В каждом из следующих анализов три алгоритма кластеризации выполнялись на новом пространстве, сгенерированном UMAP и t-SNE:

  • К-означает
  • Модель гауссовой смеси
  • Иерархическая кластеризация

УМАП

Из статьи «UMAP: Единая аппроксимация многообразия и проекция для уменьшения размерности» (Лиланд Макиннес, 2020):

UMAP (Uniform Manifold Approximation and Projection) — это новый метод обучения многообразию для уменьшения размерности. UMAP построен на теоретической основе, основанной на римановой геометрии и алгебраической топологии. Результатом является практичный масштабируемый алгоритм, применимый к данным реального мира. Алгоритм UMAP конкурирует с t-SNE по качеству визуализации и, возможно, сохраняет большую часть глобальной структуры с превосходной производительностью во время выполнения. Кроме того, UMAP не имеет вычислительных ограничений на встраивание измерений, что делает его жизнеспособным в качестве универсального метода уменьшения размеров для машинного обучения.

Вызвав библиотеку, доступную по адресу https://umap-learn.readthedocs.io/en/latest/», я могу применить UMAP к набору данных и создать новое пространство для встраивания:

# dimensionality reducer - UMAP
reducer = umap.UMAP(random_state=42)
embedding = reducer.fit_transform(X)
# embedding
df_umap = pd.DataFrame()
df_umap['embedding_x'] = embedding[:, 0]
df_umap['embedding_y'] = embedding[:, 1]# plot UMAP
sns.scatterplot(x='embedding_x', y='embedding_y', data=df_umap)

При тестировании моделей для предопределенного количества кластеров от 2 до 25 мы получаем следующие графики анализа силуэта для каждого из тестов модели:

Учитывая разумное количество кластеров (от 6 до 12), которые могут быть практически применены и интерпретированы бизнес-ориентированными командами, это оценки силуэта для каждой модели в пространстве UMAP:

В этом случае иерархическая кластеризация имеет производительность, немного превосходящую k-средние, при применении только 6 кластеров:

В результате при сортировке значений по валовому доходу видно, что кластер № 6 представляет собой покупателя с высокой ценностью или «инсайдерского» клиента, кандидата на ваучерную программу, в зависимости от бизнес-стратегии.

Теперь этот кластер представляет большую выборку нашей базы клиентов, процент 28,13% от них. Это может быть связано с низкими уровнями давности, в данном случае характерными для данной группы, поскольку все остальные кластеры имеют значительное значение средней давности. Таким образом, наиболее ценными клиентами в этой области являются не только те, кто тратит больше всего, но и те, кто тратит постоянно.

T-распределенное стохастическое встраивание соседей (t-SNE)

t-SNE – это инструмент для визуализации многомерных данных. Он преобразует сходство между точками данных в совместные вероятности и пытается минимизировать расхождение Кульбака-Лейблера между совместными вероятностями низкоразмерного вложения и многомерными данными. t-SNE имеет функцию стоимости, которая не является выпуклой, т. е. при разных инициализациях мы можем получить разные результаты.

Вызвав sklearn.manifold.TSNE, я могу применить преобразование внедрения к набору данных:

# dimensionality reducer - t-SNE
reducer = mn.TSNE(n_components=2, n_jobs=-1,random_state=42)
embedding = reducer.fit_transform(X)
# embedding
df_tsne = pd.DataFrame()
df_tsne['embedding_x'] = embedding[:, 0]
df_tsne['embedding_y'] = embedding[:, 1]# plot t-SNE
sns.scatterplot(x='embedding_x', y='embedding_y', data=df_tsne)

При тестировании моделей для предопределенного количества кластеров от 2 до 25 мы получаем следующие графики анализа силуэта для каждого из тестов модели:

Учитывая разумное количество кластеров (от 6 до 13), которые могут быть практически применены и интерпретированы бизнес-ориентированными командами, это оценки силуэта для каждой модели в пространстве t-SNE:

В этом случае K-means имеет лучшую производительность при применении только 6 кластеров:

Несмотря на то, что пространства совершенно разные, мы видим, что, объединив кластер № 1 с кластером № 6, мы получим кластер, очень похожий на кластер «инсайдеров» UMAP. В этом случае t-SNE имеет тенденцию разделять эти типы клиентов на два: один с более высоким валовым доходом, а второй с более низким валовым доходом. Но когда они вместе, они будут учитывать давность, валовой доход и процент от общего числа клиентов, очень близкий к нашему кластеру № 6 во внедрении UMAP.