724 KiB
Цель работы¶
Мы будем кластеризовать автомобили, основываясь на их характеристиках, с целью выделения групп автомобилей с похожими свойствами. Это может быть полезно, например, для автосалонов или производителей для сегментации рынка.
загрузим датасет¶
import pandas as pd
df = pd.read_csv("..//static//csv//car_price_prediction.csv", sep=",")
df
Предобработка данных¶
Мы удалим неинформативные столбцы, такие как ID, преобразуем категориальные переменные в числовые (one-hot encoding), а также нормализуем данные для дальнейшего анализа.
# Удаляем неинформативный столбец ID
df = df.drop(columns=["ID"])
# Преобразование категориальных данных в числовые с помощью one-hot encoding
df = pd.get_dummies(df, drop_first=True)
# Нормализация числовых данных
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
df_scaled = scaler.fit_transform(df)
Визуализация данных с помощью PCA (снижение размерности)¶
Для визуализации мы применим метод PCA, который уменьшит количество измерений до двух, сохраняя при этом максимальное количество информации.
Ключевые термины:
- PCA (Principal Component Analysis) — метод снижения размерности, который находит новые оси в данных, вдоль которых разброс максимален, и проецирует данные на эти оси.
- Снижение размерности — процесс упрощения данных за счёт уменьшения числа признаков.
# Импортируем PCA и визуализируем данные
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
# Применяем PCA для снижения размерности до 2
pca = PCA(n_components=2)
df_pca = pca.fit_transform(df_scaled)
# Визуализация
plt.figure(figsize=(8, 6))
plt.scatter(df_pca[:, 0], df_pca[:, 1], c='blue', edgecolor='k', alpha=0.6)
plt.title("PCA: Визуализация данных после снижения размерности")
plt.xlabel("Главная компонента 1")
plt.ylabel("Главная компонента 2")
plt.show()
Количество кластеров¶
Количество кластеров напрямую влияет на результаты кластеризации, так как оно определяет, сколько групп или сегментов будет выделено в данных. Оптимальный выбор количества кластеров важен, чтобы обеспечить баланс между точностью кластеризации и интерпретируемостью результатов.
Зачем выбирать количество кластеров?¶
Оптимальная сегментация данных¶
Разное количество кластеров может приводить к слишком мелкому делению (много мелких кластеров) или слишком крупному (слишком обобщённые кластеры). -Слишком мало кластеров: важные различия в данных могут быть упущены. -Слишком много кластеров: анализ становится сложным, и кластеры могут быть избыточно раздроблены.
Интерпретируемость результатов¶
Оптимальное количество кластеров делает результаты понятными и полезными. Например, выделение 3-5 кластеров может быть удобно для анализа, тогда как 15-20 кластеров усложнят интерпретацию.
Избежание переобучения или недообучения¶
Количество кластеров влияет на обобщающую способность модели. Слишком большое количество кластеров может привести к переобучению (модель подстраивается под шум), а слишком малое — к упрощению и игнорированию важных данных.
Практическая применимость¶
В бизнес-задачах обычно требуется понятное разделение данных. Например, если мы сегментируем клиентов, 3-5 кластеров проще использовать для таргетинга, чем 20.
Определение оптимального количества кластеров¶
Для выбора количества кластеров мы применим:
- Метод локтя — измеряет инерцию (размерность ошибок внутри кластеров).
- Коэффициент силуэта — показывает, насколько хорошо объекты распределены между кластерами.
Ключевые термины:
- Инерция — сумма квадратов расстояний от точек до центроидов их кластеров. Чем меньше, тем лучше.
- Коэффициент силуэта — оценивает плотность внутри кластеров и разницу между ними (от -1 до 1).
# Метод локтя
from sklearn.cluster import KMeans
border_l = 2
border_r = 5
inertia = []
for k in range(border_l, border_r):
kmeans = KMeans(n_clusters=k, random_state=42)
kmeans.fit(df_scaled)
inertia.append(kmeans.inertia_)
# Визуализация метода локтя
plt.figure(figsize=(8, 6))
plt.plot(range(border_l, border_r), inertia, marker='o')
plt.title('Метод локтя для выбора количества кластеров')
plt.xlabel('Количество кластеров')
plt.ylabel('Инерция')
plt.show()
# Коэффициент силуэта
from sklearn.metrics import silhouette_score
silhouette_scores = []
for k in range(border_l, border_r):
kmeans = KMeans(n_clusters=k, random_state=42)
kmeans.fit(df_scaled)
score = silhouette_score(df_scaled, kmeans.labels_)
silhouette_scores.append(score)
# Визуализация коэффициента силуэта
plt.figure(figsize=(8, 6))
plt.plot(range(border_l, border_r), silhouette_scores, marker='o')
plt.title('Коэффициент силуэта для различных кластеров')
plt.xlabel('Количество кластеров')
plt.ylabel('Коэффициент силуэта')
plt.show()
Кластеризация с помощью K-means¶
После выбора оптимального числа кластеров (например, 3), мы применим K-means для кластеризации и визуализируем результаты.
Ключевой термин:
- K-means — алгоритм кластеризации, который группирует данные вокруг центров (центроидов) кластеров.
# Кластеризация с помощью K-means
optimal_clusters = 3
kmeans = KMeans(n_clusters=optimal_clusters, random_state=42)
df['Cluster'] = kmeans.fit_predict(df_scaled)
# Визуализация кластеров с использованием PCA
plt.figure(figsize=(8, 6))
plt.scatter(df_pca[:, 0], df_pca[:, 1], c=df['Cluster'], cmap='viridis', edgecolor='k', alpha=0.6)
plt.title("Кластеры, определенные K-means (PCA)")
plt.xlabel("Главная компонента 1")
plt.ylabel("Главная компонента 2")
plt.colorbar(label='Кластер')
plt.show()
Иерархическая кластеризация¶
Применяем иерархическую кластеризацию для сравнения. Также строим дендрограмму.
Ключевой термин:
- Иерархическая кластеризация — метод, который строит древовидную структуру кластеров (дендрограмму).
from sklearn.cluster import AgglomerativeClustering
from scipy.cluster.hierarchy import dendrogram
import numpy as np
import matplotlib.pyplot as plt
# Применение иерархической кластеризации
hierarchical = AgglomerativeClustering(n_clusters=optimal_clusters)
df['Hierarchical Cluster'] = hierarchical.fit_predict(df_scaled)
# Функция для получения матрицы linkage
def get_linkage_matrix(model: AgglomerativeClustering) -> np.ndarray:
counts = np.zeros(model.children_.shape[0]) # type: ignore
n_samples = len(model.labels_)
for i, merge in enumerate(model.children_): # type: ignore
current_count = 0
for child_idx in merge:
if child_idx < n_samples:
current_count += 1
else:
current_count += counts[child_idx - n_samples]
counts[i] = current_count
return np.column_stack([model.children_, model.distances_, counts]).astype(float)
# Построение дендрограммы
linkage_matrix = get_linkage_matrix(hierarchical)
plt.figure(figsize=(12, 8))
dendrogram(linkage_matrix)
plt.title("Дендограмма, восстановленная из модели AgglomerativeClustering")
plt.xlabel("Индексы объектов")
plt.ylabel("Евклидово расстояние")
plt.show()
# Визуализация кластеров
plt.figure(figsize=(8, 6))
plt.scatter(df_pca[:, 0], df_pca[:, 1], c=df['Hierarchical Cluster'], cmap='viridis', edgecolor='k', alpha=0.6)
plt.title("Кластеры, определенные иерархической кластеризацией (PCA)")
plt.xlabel("Главная компонента 1")
plt.ylabel("Главная компонента 2")
plt.colorbar(label='Кластер')
plt.show()
Оценка качества кластеризации¶
Оценим качество кластеров, сравнив коэффициенты силуэта для двух методов.
# Оценка качества
silhouette_kmeans = silhouette_score(df_scaled, df['Cluster'])
silhouette_hierarchical = silhouette_score(df_scaled, df['Hierarchical Cluster'])
print(f"Коэффициент силуэта для K-means: {silhouette_kmeans:.4f}")
print(f"Коэффициент силуэта для иерархической кластеризации: {silhouette_hierarchical:.4f}")