992 KiB
Анализ популяции с применением метода кластеризации¶
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from scipy.cluster.hierarchy import dendrogram, linkage, fcluster
from sklearn.cluster import KMeans
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import silhouette_score
df = pd.read_csv(
".//static//csv///world-population-by-country-2020.csv", index_col="no"
)
df["Population2020"] = df["Population2020"].apply(lambda x: int("".join(x.split(","))))
df["NetChange"] = df["NetChange"].apply(lambda x: int("".join(x.split(","))))
df["Yearly Change"] = df["Yearly Change"].apply(lambda x: float("".join(x.rstrip("%"))))
df["LandArea"] = df["LandArea"].apply(lambda x: int("".join(x.split(","))))
df["Density"] = df["Density"].apply(lambda x: int("".join(x.split(","))))
df.head()
df.describe()
# Процент пропущенных значений признаков
for i in df.columns:
null_rate = df[i].isnull().sum() / len(df) * 100
if null_rate > 0:
print(f'{i} Процент пустых значений: %{null_rate:.2f}')
print(df.isnull().sum())
print(df.isnull().any())
# Проверка типов столбцов
df.dtypes
Цель: Кластеризация популяций стран для определения схожих характеристик.
Очистка данных¶
# Удалим несущественные столбцы
columns_to_drop = [
"Migrants (net)",
"Fert. Rate",
"Med. Age",
"Urban Pop %",
"Country (or dependency)",
"World Share",
]
df_cleaned = df.drop(columns=columns_to_drop)
print(df_cleaned.head()) # Вывод очищенного DataFrame
Визуализация парных взаимосвязей¶
# Настройка стиля графиков
sns.set(style="whitegrid")
# Создание фигуры
plt.figure(figsize=(15, 10))
plt.subplot(2, 2, 1)
sns.scatterplot(x=df_cleaned["NetChange"], y=df_cleaned["Population2020"], alpha=0.6, color="purple")
plt.title("NetChange vs Population2020")
plt.xlabel('NetChange')
plt.ylabel("Population2020")
plt.subplot(2, 2, 2)
sns.scatterplot(
x=df_cleaned["LandArea"],
y=df_cleaned["Population2020"],
alpha=0.6,
color="green",
)
plt.title("LandArea vs Population2020")
plt.xlabel("LandArea")
plt.ylabel("Population2020")
plt.subplot(2, 2, 3)
sns.scatterplot(
x=df_cleaned["LandArea"], y=df_cleaned["Yearly Change"], alpha=0.6, color="red"
)
plt.title("LandArea vs Yearly Change")
plt.xlabel("LandArea")
plt.ylabel("Yearly Change")
plt.subplot(2, 2, 4)
sns.scatterplot(x=df_cleaned["LandArea"], y=df_cleaned["Density"], alpha=0.6, color="red")
plt.title("LandArea vs Density")
plt.xlabel("LandArea")
plt.ylabel("Density")
plt.tight_layout()
plt.show()
Стандартизация данных для кластеризации¶
# Нормализация данных
scaler = StandardScaler()
data_scaled = scaler.fit_transform(df_cleaned)
# Преобразование в DataFrame для удобства
df_scaled = pd.DataFrame(data_scaled, columns=df_cleaned.columns)
# Понижение размерности до 2 компонент
pca = PCA(n_components=2)
kc_pca = pca.fit_transform(df_scaled)
# Визуализация
plt.figure(figsize=(8, 6))
plt.scatter(kc_pca[:, 0], kc_pca[:, 1], alpha=0.6)
plt.title("PCA Visualization")
plt.xlabel("Principal Component 1")
plt.ylabel("Principal Component 2")
plt.show()
Агломеративная (иерархическая) кластеризация¶
# Построение дендрограммы
linkage_matrix = linkage(data_scaled, method='ward')
plt.figure(figsize=(10, 7))
dendrogram(linkage_matrix)
plt.title('Дендрограмма агломеративной кластеризации')
plt.xlabel('Индекс образца')
plt.ylabel('Расстояние')
plt.show()
# Получение результатов кластеризации с заданным порогом
result = fcluster(linkage_matrix, t=60, criterion='distance')
print(result) # Вывод результатов кластеризации
# Выбираем подмножество данных для кластеризации
features = df[["NetChange", "LandArea", "Density", "Yearly Change", "Population2020"]]
scaled_features = scaler.fit_transform(features)
# Построение дендрограммы
linkage_matrix = linkage(scaled_features, method='ward') # Метод "Ward"
plt.figure(figsize=(12, 8))
dendrogram(linkage_matrix, labels=df.index, leaf_rotation=90, leaf_font_size=10)
plt.title('Иерархическая кластеризация (дендрограмма)')
plt.xlabel('Индекс')
plt.ylabel('Евклидово расстояние')
plt.tight_layout()
plt.show()
Визуализация распределения кластеров
# Визуализация кластеров
plt.figure(figsize=(14, 12))
plt.subplot(2, 2, 1)
sns.scatterplot(
x=df_cleaned["LandArea"],
y=df_cleaned["Density"],
hue=result,
palette="Set1",
alpha=0.6,
)
plt.title("LandArea vs Density")
plt.xlabel("LandArea")
plt.ylabel("Density")
plt.subplot(2, 2, 2)
sns.scatterplot(
x=df_cleaned["NetChange"],
y=df_cleaned["Yearly Change"],
hue=result,
palette="Set1",
alpha=0.6,
)
plt.title("NetChange vs Yearly Change")
plt.xlabel("NetChange")
plt.ylabel("Yearly Change")
plt.subplot(2, 2, 3)
sns.scatterplot(
x=df_cleaned["NetChange"],
y=df_cleaned["Population2020"],
hue=result,
palette="Set1",
alpha=0.6,
)
plt.title("NetChange vs Population2020")
plt.xlabel("NetChange")
plt.ylabel("Population2020")
plt.subplot(2, 2, 4)
sns.scatterplot(
x=df_cleaned["Density"],
y=df_cleaned["Yearly Change"],
hue=result,
palette="Set1",
alpha=0.6,
)
plt.title("Density vs Yearly Change")
plt.xlabel("Density")
plt.ylabel("Yearly Change")
# Настройка графиков
plt.tight_layout()
plt.show()
KMeans (неиерархическая кластеризация) для сравнения¶
features_used = [
'NetChange','LandArea','Density','Yearly Change','Population2020'
]
data_to_scale = df_cleaned[features_used]
scaler = StandardScaler()
data_scaled = scaler.fit_transform(data_to_scale)
random_state = 42
kmeans = KMeans(n_clusters=4, random_state=random_state)
labels = kmeans.fit_predict(data_scaled)
centers = kmeans.cluster_centers_
# Отображение центроидов
centers_original = scaler.inverse_transform(centers) # Обратная стандартизация
print("Центры кластеров:\n", centers_original)
# Визуализация результатов кластеризации KMeans
plt.figure(figsize=(16, 12))
plt.subplot(2, 2, 1)
sns.scatterplot(
x=df_cleaned["LandArea"],
y=df_cleaned["Population2020"],
hue=labels,
palette="Set1",
alpha=0.6,
)
plt.scatter(centers[:, 0], centers[:, 1], s=300, c='cyan', label='Centroids')
plt.title("KMeans Clustering: LandArea vs Population2020")
plt.legend()
plt.subplot(2, 2, 2)
sns.scatterplot(
x=df_cleaned["Density"],
y=df_cleaned["Population2020"],
hue=labels,
palette="Set1",
alpha=0.6,
)
plt.scatter(centers[:, 2], centers[:, 3], s=300, c='cyan', label='Centroids')
plt.title("KMeans Clustering: Density vs Population2020")
plt.legend()
plt.subplot(2, 2, 3)
sns.scatterplot(
x=df_cleaned["NetChange"],
y=df_cleaned["Yearly Change"],
hue=labels,
palette="Set1",
alpha=0.6,
)
plt.scatter(centers[:, 1], centers[:, 3], s=300, c='cyan', label='Centroids')
plt.title("KMeans Clustering: NetChange vs Yearly Change")
plt.legend()
plt.tight_layout()
plt.show()
PCA для визуализации сокращенной размерности¶
pca = PCA(n_components=2)
reduced_data = pca.fit_transform(data_scaled)
# Визуализация сокращенных данных
plt.figure(figsize=(16, 6))
plt.subplot(1, 2, 1)
sns.scatterplot(x=reduced_data[:, 0], y=reduced_data[:, 1], hue=result, palette='Set1', alpha=0.6)
plt.title('PCA reduced data: Agglomerative Clustering')
plt.subplot(1, 2, 2)
sns.scatterplot(x=reduced_data[:, 0], y=reduced_data[:, 1], hue=labels, palette='Set1', alpha=0.6)
plt.title('PCA reduced data: KMeans Clustering')
plt.tight_layout()
plt.show()
Анализ инерции для метода локтя (метод оценки суммы квадратов расстояний)¶
inertias = []
clusters_range = range(1, 11)
for i in clusters_range:
kmeans = KMeans(n_clusters=i, random_state=random_state)
kmeans.fit(data_scaled)
inertias.append(kmeans.inertia_)
plt.figure(figsize=(10, 6))
plt.plot(clusters_range, inertias, marker='o')
plt.title('Метод локтя для оптимального k')
plt.xlabel('Количество кластеров')
plt.ylabel('Инерция')
plt.grid(True)
plt.show()
Расчет коэффициентов силуэта¶
silhouette_scores = []
for i in clusters_range[1:]:
kmeans = KMeans(n_clusters=i, random_state=random_state)
labels = kmeans.fit_predict(data_scaled)
score = silhouette_score(data_scaled, labels)
silhouette_scores.append(score)
# Построение диаграммы значений силуэта
plt.figure(figsize=(10, 6))
plt.plot(clusters_range[1:], silhouette_scores, marker='o')
plt.title('Коэффициенты силуэта для разных k')
plt.xlabel('Количество кластеров')
plt.ylabel('Коэффициент силуэта')
plt.grid(True)
plt.show()
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import silhouette_score
from sklearn.cluster import KMeans
# ========================
# Применение K-Means
# ========================
kmeans = KMeans(n_clusters=3, random_state=42)
df_clusters = kmeans.fit_predict(df_scaled)
# ========================
# Оценка качества кластеризации
# ========================
silhouette_avg = silhouette_score(df_scaled, df_clusters)
print(f'Средний коэффициент силуэта: {silhouette_avg:.3f}')
# ========================
# Визуализация кластеров
# ========================
from sklearn.decomposition import PCA
pca = PCA(n_components=2)
df_pca = pca.fit_transform(df_scaled)
plt.figure(figsize=(10, 7))
sns.scatterplot(x=df_pca[:, 0], y=df_pca[:, 1], hue=df_clusters, palette='viridis', alpha=0.7)
plt.title('Визуализация кластеров с помощью K-Means')
plt.xlabel('Первая компонентa PCA')
plt.ylabel('Вторая компонентa PCA')
plt.legend(title='Кластер', loc='upper right')
plt.show()
Средний коэффициент силуэта, равный 0.408, указывает на умеренно хорошую кластеризацию.
Средний коэффициент силуэта (silhouette score) указывает на качество кластеризации, измеряя, насколько хорошо точки внутри одного кластера близки друг к другу по сравнению с точками из других кластеров. Значения коэффициента силуэта находятся в диапазоне от -1 до 1:
1: Указывает на идеально плотные и четко разделенные кластеры.
0: Указывает на перекрытие кластеров или слабую структуру кластеризации.
Отрицательные значения: Указывают, что точки в кластере расположены ближе к другому кластеру, чем к своему.
from sklearn.cluster import AgglomerativeClustering
# ========================
# Агломеративная кластеризация
# ========================
agg_cluster = AgglomerativeClustering(n_clusters=3)
labels_agg = agg_cluster.fit_predict(df_scaled)
# ========================
# Оценка качества кластеризации
# ========================
silhouette_avg_agg = silhouette_score(df_scaled, labels_agg)
print(f'Средний коэффициент силуэта (агломеративная кластеризация): {silhouette_avg_agg:.3f}')
# ========================
# Визуализация кластеров
# ========================
pca = PCA(n_components=2)
df_pca = pca.fit_transform(df_scaled)
plt.figure(figsize=(10, 7))
sns.scatterplot(x=df_pca[:, 0], y=df_pca[:, 1], hue=labels_agg, palette='viridis', alpha=0.7)
plt.title('Визуализация кластеров с помощью агломеративной кластеризации')
plt.xlabel('Первая компонентa PCA')
plt.ylabel('Вторая компонентa PCA')
plt.legend(title='Кластер', loc='upper right')
plt.show()
Значение коэффициента силуэта лежит в диапазоне от -1 до 1. Ближе к 1: Хорошо сформированные, плотные кластеры, четко отделенные друг от друга.
Ближе к 0: Кластеры пересекаются или слабо разделены, не имеют четких границ. Точки расположены одинаково близко как к своему кластеру, так и к соседним.
Ближе к -1 (Отрицательные значения): Некоторые точки скорее относятся к другим кластерам, чем к текущему (ближе к центрам других кластеров). Очень плохая кластеризация.
Ближе к 1: Все точки внутри каждого кластера плотно сгруппированы и значительно удалены от точек других кластеров. Свидетельствует о четкой и хорошо разделенной структуре данных. Единица говорит об идеальной кластеризации.