基于Python的K-means聚类案例
K-Means聚类简介
K-Means是一种广泛使用的聚类算法,它将数据点划分为K个簇(clusters),使得簇内的点尽可能相似,而簇间的点尽可能不同。K-Means算法简单、高效,适用于各种规模的数据集。
算法步骤
-
选择K值:确定要将数据划分为K个簇。
-
初始化中心点:随机选择K个数据点作为初始的簇中心(centroids)。
-
分配数据点:将每个数据点分配给最近的簇中心,形成K个簇。
-
更新中心点:计算每个簇的中心点(所有簇内点的均值),并更新簇中心。
-
重复步骤3和4:直到簇中心不再发生变化或达到最大迭代次数。
K值的选择
选择K值是K-Means聚类的关键步骤,常见的方法有:
肘部法则(Elbow Method):通过绘制不同K值下的SSE图,选择SSE显著下降的拐点作为K值。
轮廓系数(Silhouette Score):轮廓系数衡量了簇内相似度和簇间差异度,值越高表示聚类效果越好。选择轮廓系数最大的K值。
K-Means的优缺点
优点:
简单、易于实现。
对大数据集表现良好。
可以处理多维数据。
缺点:
需要预先指定K值。
对初始簇中心敏感,可能导致局部最优解。
对噪声和异常值敏感。
假设簇是凸形的,可能无法识别非凸形簇。
K-Means的变体和改进
K-Means++:改进的初始化方法,选择初始簇中心时考虑距离,以提高算法的收敛速度和聚类效果。
Mini-Batch K-Means:使用小批量数据进行迭代,提高算法的计算效率,适用于大规模数据集。
Hierarchical K-Means:结合层次聚类和K-Means,先进行层次聚类,再应用K-Means,以提高聚类效果。
应用场景
客户细分:根据客户的消费行为、偏好等特征,将客户划分为不同的群体,以便企业针对不同群体制定个性化的营销策略。
图像分割:将图像中的像素根据颜色、纹理等特征进行聚类,从而实现图像的分割,例如将一幅自然图像分割为天空、大地、树木等不同的区域。
文本分类:对文本数据进行聚类,将相似主题的文本归为一类,有助于文本的组织和检索。
生物学中的物种分类:根据生物的特征数据,将不同的生物样本聚类为不同的物种或亚种。
案例
数据加载
数据为某年各省级行政区环境污染状况的统计数据(已经经过标准化处理),包括生活污水排放量(x1),生活二氧化硫排放量(x2),生活烟尘排放量(x3),工业固体废物排放量(x4),工业废气排放总量(x5),工业废水排放量(x6),GDP水平(gdp)以及地理位置(geo)等。
# 导入相关库
# pandas 是一个用于数据处理和分析的强大库,通常用于读取、处理和操作表格数据
import pandas as pd
# numpy 是 Python 的一个基础科学计算库,提供了高效的多维数组对象和各种数学函数
import numpy as np
# 从 sklearn 库的 cluster 模块中导入 KMeans 类,用于进行 K-Means 聚类分析
from sklearn.cluster import KMeans
# 从 sklearn 库的 decomposition 模块中导入 PCA 类,用于进行主成分分析,可用于数据降维
from sklearn.decomposition import PCA
# 导入 matplotlib 库的 pyplot 模块,用于绘制各种可视化图表
import matplotlib.pyplot as plt
# 从 sklearn 库的 metrics 模块中导入 silhouette_score 函数,用于计算轮廓系数,评估聚类效果
from sklearn.metrics import silhouette_score
# 设置 matplotlib 绘图时的字体为黑体,以支持中文显示
plt.rcParams['font.sans-serif'] = ['SimHei']
# 设置 matplotlib 正确显示负号,避免负号显示异常
plt.rcParams['axes.unicode_minus'] = False
# 使用 pandas 的 read_excel 函数读取指定路径下的 Excel 文件
# r'C:\Users\21086\Desktop\数据分析实训数据\环境污染数据.xlsx' 是文件的绝对路径
# 其中 r 表示原始字符串,可避免反斜杠 \ 被转义
df = pd.read_excel(r'C:\Users\21086\Desktop\数据分析实训数据\环境污染数据.xlsx')
返回数据集的前 5 行数据
df.head()
province x1 x2 x3 x4 x5 x6 gdp geo 0 北京 21.76 15.01 12.23 0.02 10.69 3.09 2 1 1 天津 7.47 4.19 4.80 0.00 11.44 7.68 3 1 2 河北 21.92 43.49 69.43 9.40 100.00 45.79 2 1 3 山西 13.79 58.94 93.45 100.00 44.60 15.04 3 1 4 内蒙古 7.44 37.97 69.87 2.16 37.87 9.02 3 1
确定最佳聚类数
根据肘部法和轮廓系数法
# 提取特征(排除非数值列)
features = df[['x1', 'x2', 'x3', 'x4', 'x5', 'x6', 'gdp']]
# 初始化两个列表,用于存储不同聚类数下的 SSE 和轮廓系数
sse = [] # SSE(误差平方和)值列表
silhouette_scores = [] # 轮廓系数列表
# 通过循环尝试不同的聚类数(从2到10),以确定最佳的聚类数
for k in range(2, 11):
# 创建 KMeans 实例,指定聚类数为 k,设置随机种子为 42 以保证结果可复现
kmeans = KMeans(n_clusters=k, random_state=42)
# 用特征数据拟合 KMeans 模型
kmeans.fit(features)
# 计算并存储当前聚类数下的 SSE 值
sse.append(kmeans.inertia_) # inertia_ 属性存储 SSE 值
# 计算轮廓系数,轮廓系数是聚类效果好坏的一个指标,范围在 -1 到 1 之间
# 轮廓系数越高,聚类效果越好
labels = kmeans.labels_
silhouette_avg = silhouette_score(features, labels)
# 存储当前聚类数下的轮廓系数
silhouette_scores.append(silhouette_avg)
# 设置绘图的画布大小
plt.figure(figsize=(12, 6))
# 创建子图,1行2列的第1个图
plt.subplot(1, 2, 1)
# 绘制肘部法则图,显示不同聚类数下的 SSE 值
plt.plot(range(2, 11), sse, marker='o', linestyle='--')
plt.xlabel('Number of Clusters') # 设置 x 轴标签
plt.ylabel('Sum of Squared Errors (SSE)') # 设置 y 轴标签
plt.title('Elbow Method for Optimal Cluster Number') # 设置图标题
plt.grid(True) # 显示网格
# 创建子图,1行2列的第2个图
plt.subplot(1, 2, 2)
# 绘制轮廓系数图,显示不同聚类数下的轮廓系数
plt.plot(range(2, 11), silhouette_scores, marker='o', linestyle='--', color='orange')
plt.xlabel('Number of Clusters') # 设置 x 轴标签
plt.ylabel('Silhouette Score') # 设置 y 轴标签
plt.title('Silhouette Score for Optimal Cluster Number') # 设置图标题
plt.grid(True) # 显示网格
# 自动调整子图间距,避免标签重叠
plt.tight_layout()
# 显示图形
plt.show()
这段代码的目的是通过肘部法则(Elbow Method)和轮廓系数(Silhouette Score)来确定最佳的聚类数。尝试了从2到10的不同聚类数,并计算了每个聚类数下的 SSE 值和轮廓系数。然后绘制了两个图:一个显示 SSE 值随聚类数变化的图(肘部法则图),另一个显示轮廓系数随聚类数变化的图。综合肘部法则和轮廓系数的结果,聚类数为4是最佳选择。在这个聚类数下,SSE的减少幅度开始变小,同时轮廓系数达到最高,表明聚类效果较好。
。
模型训练
# 执行K-means聚类(选择k=4)
kmeans = KMeans(n_clusters=4, random_state=42)
df['cluster'] = kmeans.fit_predict(features)
聚类可视化
# 导入PCA类,用于执行主成分分析
from sklearn.decomposition import PCA
# 初始化PCA对象,设置主成分的数量为2,即我们希望将数据降维到二维空间
pca = PCA(n_components=2)
# 使用PCA对特征数据进行降维处理,fit_transform方法既拟合PCA模型,又将数据转换到主成分空间
principal_components = pca.fit_transform(features)
# 将降维后的数据添加到原始DataFrame中,以便后续可视化
df['pca1'] = principal_components[:, 0] # 第一主成分
df['pca2'] = principal_components[:, 1] # 第二主成分
# 设置绘图的画布大小
plt.figure(figsize=(12,8))
# 创建散点图,用于可视化降维后的数据
# c参数指定颜色,这里使用df['cluster']列的值来为不同簇的点指定不同的颜色
# cmap参数指定颜色映射,s参数指定点的大小
scatter = plt.scatter(df['pca1'], df['pca2'], c=df['cluster'], cmap='tab10', s=100)
# 设置x轴和y轴的标签,fontsize参数指定字体大小
plt.xlabel('Principal Component 1', fontsize=12)
plt.ylabel('Principal Component 2', fontsize=12)
# 设置图的标题,fontsize参数指定字体大小
plt.title('Cluster Visualization with PCA', fontsize=14)
# 添加省份标签
# 遍历每个省份,使用annotate方法在对应的点旁边添加文本标签
for i, txt in enumerate(df['province']):
plt.annotate(txt, (df['pca1'][i], df['pca2'][i]),
textcoords="offset points", xytext=(0,5), ha='center')
# textcoords参数指定文本标签的坐标系,offset points表示相对于点的坐标偏移
# xytext参数指定偏移量,(0,5)表示在点的正上方5个单位处添加标签
# ha参数指定水平对齐方式,center表示居中对齐
# 添加颜色条,用于指示不同簇的颜色
plt.colorbar(scatter, label='Cluster')
# 添加网格线,linestyle参数指定网格线的样式,alpha参数指定透明度
plt.grid(True, linestyle='--', alpha=0.7)
# 显示图形
plt.show()
这段代码的主要目的是使用PCA对特征数据进行降维,并可视化降维后的数据,以便观察不同簇的分布情况。通过添加省份标签,我们可以更直观地了解每个点对应的省份。颜色条则帮助我们区分不同的簇。
聚类特征分析
# 仅选择数值列进行聚合
cluster_profile = df.groupby('cluster').mean(numeric_only=True).T
print("聚类特征均值分析:")
print(cluster_profile)
聚类特征均值分析: cluster 0 1 2 3 x1 15.068947 24.375714 13.790000 53.392500 x2 15.092632 48.375714 58.940000 8.335000 x3 20.432632 61.072857 93.450000 7.970000 x4 5.310000 11.761429 100.000000 1.422500 x5 13.373158 51.657143 44.600000 36.787500 x6 16.451053 35.485714 15.040000 83.692500 gdp 3.052632 2.285714 3.000000 1.500000 geo 3.947368 3.000000 1.000000 3.500000 pca1 -22.472184 44.429974 79.194924 9.191688 pca2 -6.998101 -9.960828 -69.579195 68.067225
作者:爱因斯川