Раздел 42 · Аналитика данных с нуля

Кластеризация: k-means для сегментов клиентов против RFM

middle~15 мин

без входаВойди, чтобы отмечать прогресс, вести заметки и решать задачи в редакторе. войти

Мира · маркетолог магазина настолок «Кубик»

Коллега говорит, что наши пять RFM-сегментов «придуманы руками», а машинное обучение найдёт настоящие группы само. Это правда? Если да, давай перейдём на них.

В уроке про RFM мы сами решили, где границы: давность по третям, частота порогами 1 и 2-3, пять сегментов по правилам CASE. В прошлом уроке модель училась на готовом ответе «ушёл или нет». Сегодня ответа нет совсем: алгоритм должен сам найти группы похожих клиентов. Проверим, лучше ли они правил.

Кучки на столе

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

Это и есть кластеризация. Самый известный её алгоритм, k-means, работает так:

  1. ставит на стол k центров в случайных местах;
  2. относит каждого клиента к ближайшему центру;
  3. переносит каждый центр в среднее своих клиентов;
  4. повторяет шаги 2-3, пока центры не замрут.

Клиентов берём те же 2923, что в уроке 51, с тремя признаками на 1 июля 2026: давность в днях, число заказов и сумма за вычетом возвратов.

Без масштабирования k-means видит одни рубли

Попробуем сразу, четыре кластера:

import pandas as pd
from sklearn.cluster import KMeans

customers = pd.read_csv("customers.csv")
features = ["recency_days", "frequency", "monetary"]
raw = KMeans(n_clusters=4, n_init=10, random_state=42).fit(customers[features])

Кластеры вышли ровными полосками по деньгам: до 4600 ₽, до 10 670 ₽, до 19 970 ₽ и больше. Давность почти ничего не решает, в каждом кластере есть клиенты и с заказом на прошлой неделе, и с заказом больше года назад.

Причина в расстоянии. Для k-means два клиента близки, если близки их числа. Разница в 10 000 ₽ для него в тысячу раз больше разницы в 10 дней, а заказы различаются на единицы. Разброс денег 6979 ₽, давности 138 дней, заказов 1,5: рубли забивают всё остальное.

Лечит StandardScaler из урока про линейную регрессию: из каждого признака вычитаем среднее и делим на стандартное отклонение. После этого «на одно отклонение дольше не покупал» весит столько же, сколько «на одно отклонение больше потратил».

from sklearn.preprocessing import StandardScaler

X = StandardScaler().fit_transform(customers[features])
model = KMeans(n_clusters=4, n_init=10, random_state=42).fit(X)
customers["cluster"] = model.labels_

Сколько кластеров

k выбирает аналитик. Подсказок две.

Inertia это сумма квадратов расстояний клиентов до своих центров. Она всегда падает с ростом k: при 2923 кластерах каждый клиент сам себе центр, и inertia ноль. Поэтому ищут локоть: место, после которого каждый новый кластер почти ничего не даёт.

Силуэт отвечает на другой вопрос: насколько клиент ближе к своим, чем к соседнему кластеру. Его можно сравнивать между k напрямую, ближе к 1 лучше.

from sklearn.metrics import silhouette_score

for k in range(2, 9):
    km = KMeans(n_clusters=k, n_init=10, random_state=42).fit(X)
    print(k, round(km.inertia_, 1), round(silhouette_score(X, km.labels_), 3))
kinertiaсилуэт
24931,40,458
33242,50,408
42470,30,398
52033,30,361
61784,20,368
71564,90,363
81421,40,368

От 2 к 3 кластерам inertia падает на 1689, от 3 к 4 на 772, дальше на 437 и меньше: локоть на 3-4. Силуэт лучше всего при k = 2 и медленно сползает. Два кластера Мире не помогут, «активные и неактивные» она знает и без модели. Берём k = 4: последний заметный шаг локтя, а силуэт почти как у трёх. Так обычно и бывает: метрики сужают выбор, а решает задача.

урок из курса

Урок из курса «Аналитика данных с нуля». Курс покупается один раз и остаётся навсегда: 500 ₽.

Оплата пока не подключена: премиум и курсы открываются промокодом.