УМК СПО

Учебно-методические комплексы

для преподавателей СПО








Кластеризация методом K-means

ОП.10 Машинное обучение
Практическая работа №6
Тема: Кластеризация методом K-means

Цель работы: Научиться применять алгоритм кластеризации K-means для группировки данных без меток, интерпретировать результаты, выбирать оптимальное число кластеров.
Время выполнения: 2 академических часа
Инструменты: Python + Jupyter Notebook, sklearn, matplotlib, seaborn

ЗАДАНИЕ ДЛЯ СТУДЕНТА

Этап 1. Создание данных и базовая кластеризация (15 минут)



import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import make_blobs
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import silhouette_score, adjusted_rand_score

# Создание синтетических данных (4 кластера)
X, y_true = make_blobs(n_samples=300, centers=4, cluster_std=0.8, random_state=42)

print(f"Размер данных: {X.shape}")
print(f"Реальное число кластеров: {len(np.unique(y_true))}")
print(f"Первые 5 точек:\n{X[:5]}")

# Визуализация исходных данных
plt.figure(figsize=(12, 5))

plt.subplot(1, 2, 1)
plt.scatter(X[:, 0], X[:, 1], c=y_true, cmap='viridis', s=50)
plt.title('Истинная разметка (4 кластера)')
plt.colorbar()

plt.subplot(1, 2, 2)
plt.scatter(X[:, 0], X[:, 1], s=50)
plt.title('Данные без разметки')
plt.tight_layout()
plt.show()

# Нормализация данных
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# K-means с k=4
kmeans = KMeans(n_clusters=4, random_state=42, n_init=10)
y_pred = kmeans.fit_predict(X_scaled)

# Визуализация результата
plt.figure(figsize=(8, 6))
plt.scatter(X[:, 0], X[:, 1], c=y_pred, cmap='viridis', s=50)
plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1],
c='red', marker='X', s=200, edgecolors='black', linewidths=2)
plt.title('K-means кластеризация (k=4)')
plt.show()

print(f"Silhouette Score: {silhouette_score(X_scaled, y_pred):.4f}")



Вопрос: Как визуально оценить качество кластеризации? Что означают красные крестики?

Этап 2. Метод локтя (Elbow method) (15 минут)



# Расчёт инерции для разного числа кластеров
inertias = []
K_range = range(1, 11)

for k in K_range:
kmeans = KMeans(n_clusters=k, random_state=42, n_init=10)
kmeans.fit(X_scaled)
inertias.append(kmeans.inertia_)

# Визуализация метода локтя
plt.figure(figsize=(10, 6))
plt.plot(K_range, inertias, 'o-', linewidth=2, markersize=8)
plt.xlabel('Число кластеров (k)')
plt.ylabel('Сумма квадратов расстояний (Inertia)')
plt.title('Метод локтя для выбора числа кластеров')
plt.xticks(K_range)
plt.grid(True, alpha=0.3)

# Отмечаем точку "локтя"
plt.axvline(x=4, color='r', linestyle='--', linewidth=2, label='Оптимальное k=4')
plt.legend()
plt.show()

print("Значения инерции:")
for k, inertia in zip(K_range, inertias):
print(f"k={k}: inertia={inertia:.2f}")



Вопрос: При каком значении k наблюдается «локоть»? Что это означает?

Этап 3. Силуэтный анализ (15 минут)



from sklearn.metrics import silhouette_samples

# Расчёт силуэтных коэффициентов
silhouette_scores = []
for k in range(2, 11):
kmeans = KMeans(n_clusters=k, random_state=42, n_init=10)
labels = kmeans.fit_predict(X_scaled)
score = silhouette_score(X_scaled, labels)
silhouette_scores.append(score)
print(f"k={k}: Silhouette Score = {score:.4f}")

# Визуализация
plt.figure(figsize=(10, 6))
plt.plot(range(2, 11), silhouette_scores, 'o-', linewidth=2, markersize=8)
plt.xlabel('Число кластеров (k)')
plt.ylabel('Силуэтный коэффициент')
plt.title('Силуэтный анализ для выбора числа кластеров')
plt.xticks(range(2, 11))
plt.grid(True, alpha=0.3)

best_k = range(2, 11)[np.argmax(silhouette_scores)]
plt.axvline(x=best_k, color='r', linestyle='--', linewidth=2, label=f'Оптимальное k={best_k}')
plt.legend()
plt.show()

# Визуализация силуэтных коэффициентов для каждого образца (k=4)
kmeans_4 = KMeans(n_clusters=4, random_state=42, n_init=10)
labels_4 = kmeans_4.fit_predict(X_scaled)
silhouette_vals = silhouette_samples(X_scaled, labels_4)

plt.figure(figsize=(10, 6))
y_lower = 10
for i in range(4):
cluster_vals = silhouette_vals[labels_4 == i]
cluster_vals.sort()
y_upper = y_lower + len(cluster_vals)
color = plt.cm.viridis(i / 4)
plt.fill_betweenx(np.arange(y_lower, y_upper), 0, cluster_vals, facecolor=color, alpha=0.7)
y_lower = y_upper + 10

plt.axvline(x=silhouette_score(X_scaled, labels_4), color='red', linestyle='--', label='Средний силуэт')
plt.xlabel('Силуэтный коэффициент')
plt.ylabel('Кластер')
plt.title('Силуэтный график для k=4')
plt.legend()
plt.show()



Вопрос: Какое значение k даёт максимальный силуэтный коэффициент? Как интерпретировать силуэтный график?

Этап 4. Визуализация кластеризации для разных k (15 минут)



# Кластеризация для разных k
k_values = [2, 3, 4, 5, 6]
fig, axes = plt.subplots(2, 3, figsize=(15, 10))
axes = axes.flatten()

for i, k in enumerate(k_values):
kmeans = KMeans(n_clusters=k, random_state=42, n_init=10)
labels = kmeans.fit_predict(X_scaled)
score = silhouette_score(X_scaled, labels)

axes[i].scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis', s=50)
axes[i].scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1],
c='red', marker='X', s=200, edgecolors='black')
axes[i].set_title(f'k = {k}, Silhouette = {score:.3f}')
axes[i].set_xlabel('Признак 1')
axes[i].set_ylabel('Признак 2')

# Убираем пустой подграфик
axes[5].axis('off')
plt.tight_layout()
plt.show()



Вопрос: Что происходит при k=2? При k=6? Какое k выглядит оптимальным?

Этап 5. Инициализация центроидов (10 минут)



# Сравнение разных способов инициализации
init_methods = ['random', 'k-means++']
colors = ['red', 'blue']

fig, axes = plt.subplots(1, 2, figsize=(14, 5))

for i, init in enumerate(init_methods):
kmeans = KMeans(n_clusters=4, init=init, n_init=1, random_state=42)
labels = kmeans.fit_predict(X_scaled)

axes[i].scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis', s=50)
axes[i].scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1],
c=colors[i], marker='X', s=200, edgecolors='black', linewidths=2)
axes[i].set_title(f'init = {init}, inertia = {kmeans.inertia_:.2f}')
axes[i].set_xlabel('Признак 1')
axes[i].set_ylabel('Признак 2')

plt.tight_layout()
plt.show()

print("K-means++ даёт более стабильный результат и быстрее сходится")



Вопрос: В чём разница между 'random' и 'k-means++'? Какой метод лучше и почему?

Этап 6. Практическое задание: кластеризация покупателей (20 минут)



# Создание данных о покупателях (годовой доход и расходы)
np.random.seed(42)
n_customers = 200

# Группы покупателей
group1 = np.random.normal([30000, 20000], [5000, 4000], (70, 2)) # Низкий доход, низкие расходы
group2 = np.random.normal([60000, 45000], [8000, 7000], (60, 2)) # Средний доход, средние расходы
group3 = np.random.normal([100000, 80000], [12000, 15000], (50, 2)) # Высокий доход, высокие расходы
group4 = np.random.normal([150000, 60000], [20000, 10000], (20, 2)) # Очень высокий доход, экономные

X_customers = np.vstack([group1, group2, group3, group4])
true_groups = np.array([0]*70 + [1]*60 + [2]*50 + [3]*20)

# Нормализация
scaler_cust = StandardScaler()
X_customers_scaled = scaler_cust.fit_transform(X_customers)

# Задание 1: Определите оптимальное число кластеров методом локтя
inertias_cust = []
K_range = range(1, 11)
for k in K_range:
kmeans = KMeans(n_clusters=k, random_state=42, n_init=10)
kmeans.fit(X_customers_scaled)
inertias_cust.append(kmeans.inertia_)

plt.figure(figsize=(12, 5))
plt.subplot(1, 2, 1)
plt.plot(K_range, inertias_cust, 'o-')
plt.xlabel('k')
plt.ylabel('Inertia')
plt.title('Метод локтя')

# Задание 2: Силуэтный анализ
sil_scores = []
for k in range(2, 11):
kmeans = KMeans(n_clusters=k, random_state=42, n_init=10)
labels = kmeans.fit_predict(X_customers_scaled)
sil_scores.append(silhouette_score(X_customers_scaled, labels))

plt.subplot(1, 2, 2)
plt.plot(range(2, 11), sil_scores, 'o-')
plt.xlabel('k')
plt.ylabel('Silhouette Score')
plt.title('Силуэтный анализ')
plt.tight_layout()
plt.show()

# Задание 3: Кластеризация с оптимальным k
best_k = range(2, 11)[np.argmax(sil_scores)]
print(f"Оптимальное число кластеров: {best_k}")

kmeans_final = KMeans(n_clusters=best_k, random_state=42, n_init=10)
customer_labels = kmeans_final.fit_predict(X_customers_scaled)

# Визуализация результатов
plt.figure(figsize=(12, 5))

plt.subplot(1, 2, 1)
plt.scatter(X_customers[:, 0], X_customers[:, 1], c=true_groups, cmap='viridis', s=50)
plt.xlabel('Годовой доход')
plt.ylabel('Расходы')
plt.title('Истинные группы покупателей')

plt.subplot(1, 2, 2)
plt.scatter(X_customers[:, 0], X_customers[:, 1], c=customer_labels, cmap='viridis', s=50)
plt.scatter(kmeans_final.cluster_centers_[:, 0] * scaler_cust.scale_[0] + scaler_cust.mean_[0],
kmeans_final.cluster_centers_[:, 1] * scaler_cust.scale_[1] + scaler_cust.mean_[1],
c='red', marker='X', s=200, edgecolors='black')
plt.xlabel('Годовой доход')
plt.ylabel('Расходы')
plt.title(f'K-means кластеризация (k={best_k})')
plt.tight_layout()
plt.show()

# Задание 4: Характеристики кластеров
customer_df = pd.DataFrame(X_customers, columns=['income', 'spending'])
customer_df['cluster'] = customer_labels

print("\nХарактеристики кластеров:")
for cluster in sorted(customer_df['cluster'].unique()):
cluster_data = customer_df[customer_df['cluster'] == cluster]
print(f"\nКластер {cluster}:")
print(f" Количество: {len(cluster_data)}")
print(f" Средний доход: {cluster_data['income'].mean():.0f}")
print(f" Средние расходы: {cluster_data['spending'].mean():.0f}")



Вопрос: Сколько типов покупателей выделил алгоритм? Как можно охарактеризовать каждый кластер?

Этап 7. Выводы (10 минут)

Напишите вывод, ответив на вопросы:
1. Как работает алгоритм K-means? Каков принцип его работы?
2. Как выбрать оптимальное число кластеров? Какие методы вы использовали?
3. Что такое инерция и силуэтный коэффициент? В чём их преимущества и недостатки?
4. В каких реальных задачах может применяться кластеризация?

КРИТЕРИИ ОЦЕНКИ

КритерийМакс. балл
Базовая кластеризация выполнена1
Метод локтя выполнен и проанализирован2
Силуэтный анализ выполнен2
Визуализация для разных k выполнена2
Эксперимент с инициализацией проведён1
Практическое задание выполнено и выводы написаны2
Итого10


Автор: УМК СПО
Лицензия: Бесплатное использование с указанием источника





Логин: Пароль: Забыли пароль?Регистрация

Самозанятый: Стешенко Светлана Николаевна ИНН: 231408226339

Актуальная версия — 2026
Сайт сделан на SiNG cms © 2010-2020