K-Means聚类分析以及误差平方和SSE(Python实现)
K-means聚类的原理。
K-Means算法的目标是将原始数据分为K簇,每一簇都有一个中心点,这也是簇中点的均值点,簇中所有的点到所属的簇的中心点的距离都比到其他簇的中心点更近。
K-means聚类的算法流程。
1、随机确定K个点作为质心。
2、找到离每个点最近的质心,将这个点分配到这个质心代表的簇里。
3、再对每个簇进行计算,以点簇的均值点作为新的质心。
4、如果新的质心和上一轮的不一样,则迭代进行2-3步骤,直到质心位置稳定。
代码介绍
使用 make_blobs 函数生成一个二维的随机数据集,包含120个样本和3个中心。生成的数据将用于后续的聚类分析。
数据生成后,通过散点图可视化这些点,展示不同的聚类中心。
定义了一个函数 calculate_sse,用于计算给定聚类数 k 时的误差平方和(SSE)。该函数使用K-Means算法进行聚类,并返回聚类后的SSE值。
# 导入必要的库
import numpy as np # 用于数值计算
import matplotlib.pyplot as plt # 用于数据可视化
from sklearn.datasets import make_blobs # 用于生成聚类数据
from sklearn.cluster import KMeans # 用于K-Means聚类算法
# 1. 生成数据
X, y_true = make_blobs(n_samples=120, n_features=2, centers=3, random_state=42) # 生成120个样本,2个特征,3个聚类中心
# 可视化生成的数据
# 设置matplotlib的字体为中文和负号的显示
plt.rcParams["font.sans-serif"] = ["SimHei"] # 使绘图时中文正确显示
plt.rcParams["axes.unicode_minus"] = False # 使绘图时负号正确显示
plt.scatter(X[:, 0], X[:, 1], s=30) # 绘制散点图
plt.title("初始数据") # 图表标题
plt.xlabel("特征 1") # x轴标签
plt.ylabel("特征 2") # y轴标签
plt.show() # 显示图形
# 2. 定义计算SSE的函数
def calculate_sse(X, k):
kmeans = KMeans(n_clusters=k, random_state=42) # 初始化K-Means算法,指定聚类数量k
kmeans.fit(X) # 进行聚类
sse = kmeans.inertia_ # 获取聚类的误差平方和(SSE)
return sse # 返回SSE值
# 3. 执行聚类并记录SSE
sse_list = [] # 初始化一个列表用于存储不同K值的SSE
k_values = range(1, 11) # 定义K的范围,从1到10
n_trials = 5 # 每个K值进行5次实验以降低随机性影响
for k in k_values: # 遍历每一个K值
sse_trials = [] # 记录每个K值的SSE试验结果
for _ in range(n_trials): # 进行n_trials次实验
sse = calculate_sse(X, k) # 计算当前K值下的SSE
sse_trials.append(sse) # 将结果保存到列表
avg_sse = np.mean(sse_trials) # 计算当前K值的平均SSE
sse_list.append(avg_sse) # 将平均SSE保存到sse_list中
# 4. 输出K值与平均SSE关系数据
print("K值与平均SSE关系:") # 打印说明
for k, sse in zip(k_values, sse_list): # 遍历K值及其对应的平均SSE
print(f"K = {k}, 平均 SSE = {sse:.2f}") # 格式化输出K值及其对应的平均SSE
# 将输出保存到文件
with open("sse_results.txt", "w") as file: # 打开文件以写入
file.write("K值与平均SSE关系:\n") # 写入文件标题
for k, sse in zip(k_values, sse_list): # 遍历K值及其对应的平均SSE
file.write(f"K = {k}, 平均 SSE = {sse:.2f}\n") # 保存K值和平均SSE到文件中
print("SSE数据已保存到 sse_results.txt 文件中") # 输出保存成功的提示信息
# 5. 绘制K值与平均SSE关系图
plt.plot(k_values, sse_list, marker='o') # 绘制K值与平均SSE的折线图,并使用圆点标记
plt.title("平均SSE vs 簇数量(K)") # 图表标题
plt.xlabel("簇个数(K)") # x轴标签
plt.ylabel("平均 SSE") # y轴标签
plt.xticks(k_values) # 设置x轴刻度
plt.grid() # 添加网格
plt.show() # 显示图形
# 6. 使用最佳K值重新进行聚类并可视化结果
best_k = 3 # 假设最优的K值为3
kmeans = KMeans(n_clusters=best_k, random_state=42) # 初始化K-Means算法
y_kmeans = kmeans.fit_predict(X) # 进行聚类并返回每个样本的聚类标签
# 可视化聚类结果
plt.scatter(X[:, 0], X[:, 1], c=y_kmeans, s=30, cmap='viridis') # 绘制聚类结果的散点图,颜色代表不同聚类
centers = kmeans.cluster_centers_ # 获取聚类中心
plt.scatter(centers[:, 0], centers[:, 1], c='red', s=200, alpha=0.75, marker='X') # 绘制聚类中心
plt.title(f"K={best_k}的K- means聚类") # 图表标题
plt.xlabel("特征 1") # x轴标签
plt.ylabel("特征 2") # y轴标签
plt.show() # 显示聚类结果图
运行结果:
为了确定最佳的聚类数量K,代码计算从1到10的不同K值对应的平均SSE。每个K值重复进行5次实验,以减少随机性对结果的影响。
计算好的平均SSE值被存储在一个列表中,并最终输出至控制台以显示K值与SSE的关系。
将K值与平均SSE的关系写入到一个文本文件中,方便后续查看和分析。
使用折线图将K值与对应的平均SSE可视化,直观展示聚类数量对聚类效果的影响。
由左至右k=1,2,3,4,5,6,7,SSE会随着K的变大而减小。可以看出在k= 3之后,随着k的增大,SSE的下降减缓了,再增加K得到的聚合回报变小,也就是k=3应该为最佳聚类数。
结合其他k值的图像,当K=2时,数据点的分类其实是不充分的。而当K=4时,数据点上方十分密集的数据点却经常因为右上角噪音点的影响被从中间分成两簇,这是不符合实际情况的,当k>3时,聚类结果就会显得愈加杂乱。结合图像,K=3仍然是最好的选择。
由图得出最佳的K值为3,重新使用K-Means算法进行聚类,并可视化聚类结果。每个聚类用不同的颜色标记,并且绘制出聚类中心,以便清晰了解聚类的效果。