跳到主要内容Python 实战:肘部法则与轮廓系数可视化(K-Means 聚类最优 K 值选择) | 极客日志PythonAI算法
Python 实战:肘部法则与轮廓系数可视化(K-Means 聚类最优 K 值选择)
本文介绍使用 Python 通过肘部法则和轮廓系数确定 K-Means 聚类最优 K 值的方法。包含原理讲解、代码实现、可视化图表及避坑指南,适用于数据分析与机器学习场景。
在聚类分析中,K-Means 算法的核心难点是确定最优聚类数 K。肘部法则(Elbow Method)和轮廓系数(Silhouette Score)是两种最常用的 K 值选择方法 —— 肘部法则直观高效,轮廓系数兼顾聚类内聚性与分离性。本文将手把手教你用 Python 实现这两种方法的可视化,结合真实数据集快速找到最优 K 值,代码精简易上手,零基础也能轻松落地。
一、核心原理与环境准备
1. 核心逻辑
K 值选择的核心是'平衡聚类效果与复杂度',两种方法的原理与流程如下:
- SSE(误差平方和):每个样本到其聚类中心的距离平方和,SSE 越小表示聚类内聚性越好;肘部法则中,SSE 下降速率骤减的点即为'肘部'。
- 轮廓系数:取值范围 [-1,1],系数越接近 1 表示样本聚类越合理,越接近 -1 表示样本可能分错类,0 表示样本在两类边界。
- 工具选择:scikit-learn(实现 K-Means 与指标计算)、pandas(数据处理)、matplotlib/seaborn(可视化)。
2. 环境准备
工具 / 依赖 | 版本要求 | 作用描述 |
Python | 3.7+ | 核心运行环境 |
scikit-learn | 0.23+ | K-Means 聚类、SSE 与轮廓系数计算 |
pandas | 1.0+ | 数据处理与加载 |
matplotlib/seaborn | 3.0+/0.10+ | 可视化曲线绘制 |
numpy | 1.18+ | 数值计算支持 |
pip | 20.0+ | Python 包管理工具 |
3. 依赖安装命令
pip install scikit-learn pandas matplotlib seaborn numpy
4. 数据集准备
选用 scikit-learn 内置的 make_blobs 生成模拟聚类数据集(含 4 个真实聚类中心),也可替换为自己的数据集(如 CSV 文件):
from sklearn.datasets import make_blobs
X, y_true = make_blobs(n_samples=1000, n_features=2, centers=4, cluster_std=0.6, random_state=42)
import pandas as pd
data = pd.DataFrame(X, columns=["特征 1", "特征 2"])
print("数据集预览:")
print(data.head())
print(f"\n数据集形状:{data.shape}")
二、核心代码实现:肘部法则可视化
1. 肘部法则代码(计算 SSE + 绘制曲线)
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.cluster import KMeans
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
def elbow_method_visualization(X, k_range):
"""
肘部法则可视化
:param X: 聚类数据集(特征矩阵)
:param k_range: K 值候选集(如 range(2, 11))
:return: 各 K 值对应的 SSE 列表
"""
sse_list = []
for k in k_range:
kmeans = KMeans(n_clusters=k, random_state=42, n_init=10)
kmeans.fit(X)
sse = kmeans.inertia_
sse_list.append(sse)
print(f"K={k} 时,SSE={sse:.2f}")
plt.figure(figsize=(10, 6))
sns.lineplot(x=k_range, y=sse_list, marker='o', linewidth=2, markersize=8, color='#2E86AB')
elbow_k = 4
elbow_sse = sse_list[elbow_k - k_range.start]
plt.scatter(elbow_k, elbow_sse, color='#E74C3C', s=200, zorder=5)
plt.annotate(f'肘部点 (K={elbow_k}, SSE={elbow_sse:.2f})',
xy=(elbow_k, elbow_sse),
xytext=(elbow_k+0.5, elbow_sse+50),
arrowprops=dict(arrowstyle='->', color='#E74C3C', linewidth=2),
fontsize=12, color='#E74C3C', fontweight='bold')
plt.title('K-Means 聚类肘部法则曲线(最优 K 值选择)', fontsize=14, fontweight='bold')
plt.xlabel('聚类数 K', fontsize=12)
plt.ylabel('SSE(簇内误差平方和)', fontsize=12)
plt.grid(True, alpha=0.3)
plt.xticks(k_range)
plt.tight_layout()
plt.savefig('肘部法则曲线.png', dpi=300)
plt.show()
return sse_list
k_candidates = range(2, 11)
sse_results = elbow_method_visualization(X, k_candidates)
2. 代码解析与结果解读
(1)核心逻辑
- 遍历 K 值候选集(2-10),对每个 K 训练 K-Means 模型;
- 通过 kmeans.inertia_ 获取 SSE(簇内误差平方和),存储到列表;
- 绘制 SSE-K 曲线,寻找'肘部'(SSE 下降速率骤减的点)。
(2)结果解读
- 输出示例:K=2 时,SSE=5907.76;K=3 时,SSE=2130.48;K=4 时,SSE=546.78;K=5 时,SSE=489.52;
- 曲线特征:K 从 2 到 4 时,SSE 快速下降;K>4 后,SSE 下降速率明显变慢,因此 K=4 是肘部点,即为最优聚类数。
三、核心代码实现:轮廓系数可视化
1. 轮廓系数代码(计算系数 + 绘制曲线 + 样本轮廓图)
from sklearn.metrics import silhouette_score, silhouette_samples
def silhouette_visualization(X, k_range):
"""
轮廓系数可视化(含平均轮廓系数曲线 + 样本轮廓图)
:param X: 聚类数据集(特征矩阵)
:param k_range: K 值候选集
:return: 各 K 值对应的平均轮廓系数列表
"""
silhouette_avg_list = []
for k in k_range:
kmeans = KMeans(n_clusters=k, random_state=42, n_init=10)
cluster_labels = kmeans.fit_predict(X)
silhouette_avg = silhouette_score(X, cluster_labels)
silhouette_avg_list.append(silhouette_avg)
print(f"K={k} 时,平均轮廓系数={silhouette_avg:.4f}")
plt.figure(figsize=(10, 6))
sns.lineplot(x=k_range, y=silhouette_avg_list, marker='s', linewidth=2, markersize=8, color='#8E44AD')
best_k = k_range[np.argmax(silhouette_avg_list)]
best_score = max(silhouette_avg_list)
plt.scatter(best_k, best_score, color='#F39C12', s=200, zorder=5)
plt.annotate(f'最优 K 值 (K={best_k}, 系数={best_score:.4f})',
xy=(best_k, best_score),
xytext=(best_k+0.5, best_score-0.02),
arrowprops=dict(arrowstyle='->', color='#F39C12', linewidth=2),
fontsize=12, color='#F39C12', fontweight='bold')
plt.title('K-Means 聚类平均轮廓系数曲线(最优 K 值选择)', fontsize=14, fontweight='bold')
plt.xlabel('聚类数 K', fontsize=12)
plt.ylabel('平均轮廓系数', fontsize=12)
plt.grid(True, alpha=0.3)
plt.xticks(k_range)
plt.ylim(0, 1)
plt.tight_layout()
plt.savefig('平均轮廓系数曲线.png', dpi=300)
plt.show()
best_kmeans = KMeans(n_clusters=best_k, random_state=42, n_init=10)
best_cluster_labels = best_kmeans.fit_predict(X)
sample_silhouette_values = silhouette_samples(X, best_cluster_labels)
plt.figure(figsize=(12, 7))
y_lower = 10
for i in range(best_k):
ith_cluster_silhouette_values = sample_silhouette_values[best_cluster_labels == i]
ith_cluster_silhouette_values.sort()
size_cluster_i = ith_cluster_silhouette_values.shape[0]
y_upper = y_lower + size_cluster_i
color = plt.cm.Spectral(i / float(best_k))
plt.fill_betweenx(np.arange(y_lower, y_upper), 0, ith_cluster_silhouette_values,
facecolor=color, edgecolor=color, alpha=0.7)
plt.text(-0.05, y_lower + 0.5 * size_cluster_i, str(i),
ha='center', va='center', fontweight='bold')
y_lower = y_upper + 10
plt.axvline(x=best_score, color='#E74C3C', linestyle='--', linewidth=2, label=f'平均轮廓系数:{best_score:.4f}')
plt.title(f'K={best_k}时的样本轮廓图', fontsize=14, fontweight='bold')
plt.xlabel('轮廓系数', fontsize=12)
plt.ylabel('样本聚类编号', fontsize=12)
plt.xlim([-0.1, 1.0])
plt.ylim([0, len(X) + (best_k + 1) * 10])
plt.legend(loc='upper right')
plt.grid(True, alpha=0.3, axis='x')
plt.tight_layout()
plt.savefig(f'K={best_k}_样本轮廓图.png', dpi=300)
plt.show()
return silhouette_avg_list
silhouette_results = silhouette_visualization(X, k_candidates)
2. 代码解析与结果解读
(1)核心逻辑
- 遍历 K 值候选集,训练 K-Means 模型并获取聚类标签;
- silhouette_score 计算所有样本的平均轮廓系数;
- silhouette_samples 计算每个样本的轮廓系数,绘制样本轮廓图;
- 平均轮廓系数最大的 K 值即为最优聚类数。
(2)结果解读
- 输出示例:K=2 时,平均轮廓系数=0.5578;K=3 时,平均轮廓系数=0.6505;K=4 时,平均轮廓系数=0.7512;K=5 时,平均轮廓系数=0.6893;
- 曲线特征:K=4 时平均轮廓系数最大(0.7512),说明该 K 值的聚类效果最优;
- 样本轮廓图:每个聚类的轮廓带越宽、越接近 1,说明聚类内聚性越好;无明显负系数样本,说明无错分类样本。
四、综合最优 K 值确定与聚类效果可视化
1. 综合两种方法确定最优 K
print("\n=== 最优 K 值选择结果对比 ===")
result_df = pd.DataFrame({
'K 值': k_candidates,
'SSE': sse_results,
'平均轮廓系数': silhouette_results
})
print(result_df.to_string(index=False))
optimal_k = 4
print(f"\n综合两种方法,最优聚类数 K={optimal_k}")
2. 最优 K 值的聚类效果可视化
optimal_kmeans = KMeans(n_clusters=optimal_k, random_state=42, n_init=10)
optimal_labels = optimal_kmeans.fit_predict(X)
centers = optimal_kmeans.cluster_centers_
plt.figure(figsize=(10, 8))
sns.scatterplot(x=X[:, 0], y=X[:, 1], hue=optimal_labels, palette='viridis',
s=60, alpha=0.8, legend='full')
sns.scatterplot(x=centers[:, 0], y=centers[:, 1], color='red', s=200, marker='X',
label='聚类中心', edgecolor='black', linewidth=2)
plt.title(f'K={optimal_k}时 K-Means 聚类效果可视化', fontsize=14, fontweight='bold')
plt.xlabel('特征 1', fontsize=12)
plt.ylabel('特征 2', fontsize=12)
plt.grid(True, alpha=0.3)
plt.legend(title='聚类编号')
plt.tight_layout()
plt.savefig(f'K={optimal_k}_聚类效果可视化.png', dpi=300)
plt.show()
五、运行与测试步骤(手把手操作)
1. 前置准备
- 安装所需依赖(执行 pip install 命令);
- 复制代码到 PyCharm、VS Code 或 Jupyter Notebook。
2. 运行代码
- 按顺序执行代码(分单元格执行更易调试);
- 观察控制台输出:
- 各 K 值的 SSE 和平均轮廓系数;
- 最优 K 值选择结果;
- 查看项目目录:生成 4 张可视化图表(肘部法则曲线、平均轮廓系数曲线、样本轮廓图、聚类效果图)。
3. 验证结果
- 肘部法则曲线:找到 SSE 下降骤减的肘部点(应为 K=4);
- 轮廓系数曲线:确认 K=4 时平均轮廓系数最大;
- 聚类效果图:4 个聚类边界清晰,无明显混杂样本。
六、避坑指南(新手必看)
1. K-Means 训练不稳定
- 错误现象:相同 K 值的 SSE 或轮廓系数波动较大;
- 解决方法:设置 n_init=10(默认值,多次初始化取最优结果),或增大 n_init 至 20。
2. 肘部点不明显
- 错误现象:SSE 曲线平滑下降,无明显肘部;
- 解决方法:
- 扩大 K 值候选集(如 1-15);
- 对数据做标准化处理(StandardScaler);
- 结合轮廓系数综合判断,优先选择轮廓系数最大的 K。
3. 轮廓系数偏低(<0.5)
- 错误现象:所有 K 值的平均轮廓系数都低于 0.5;
- 解决方法:
- 检查数据是否适合聚类(如数据分布分散、无明显聚类结构);
- 对数据做降维处理(如 PCA),减少噪声特征;
- 调整 K 值范围,或尝试其他聚类算法(如 DBSCAN)。
4. 中文乱码
- 错误现象:图表中中文显示为问号;
- 解决方法:正确设置中文字体(Windows 用 SimHei,Mac 用 Arial Unicode MS)。
七、进阶扩展(按需优化)
1. 真实数据集应用(以鸢尾花数据集为例)
from sklearn.datasets import load_iris
from sklearn.preprocessing import StandardScaler
iris = load_iris()
X_iris = iris.data[:, :2]
y_iris = iris.target
scaler = StandardScaler()
X_iris_scaled = scaler.fit_transform(X_iris)
k_iris = range(2, 8)
sse_iris = elbow_method_visualization(X_iris_scaled, k_iris)
silhouette_iris = silhouette_visualization(X_iris_scaled, k_iris)
2. 自动化最优 K 值选择(无需手动标记肘部点)
def auto_select_optimal_k(sse_list, k_range):
"""自动化寻找肘部点(基于 SSE 一阶差分)"""
sse_diff = np.diff(sse_list)
sse_diff_rate = np.diff(sse_diff)
elbow_idx = np.argmax(np.abs(sse_diff_rate)) + 2
return elbow_idx
auto_optimal_k = auto_select_optimal_k(sse_results, k_candidates)
print(f"\n自动化选择的最优 K 值:{auto_optimal_k}")
3. 多特征数据可视化(结合 PCA 降维)
from sklearn.decomposition import PCA
X_iris_full = scaler.fit_transform(iris.data)
kmeans_iris = KMeans(n_clusters=3, random_state=42, n_init=10)
labels_iris = kmeans_iris.fit_predict(X_iris_full)
pca = PCA(n_components=2)
X_iris_pca = pca.fit_transform(X_iris_full)
plt.figure(figsize=(10, 8))
sns.scatterplot(x=X_iris_pca[:, 0], y=X_iris_pca[:, 1], hue=labels_iris, palette='Set2', s=60)
plt.title('PCA 降维后 K-Means 聚类效果(鸢尾花数据集)', fontsize=14, fontweight='bold')
plt.xlabel('PCA 特征 1', fontsize=12)
plt.ylabel('PCA 特征 2', fontsize=12)
plt.grid(True, alpha=0.3)
plt.show()
总结
本文通过'原理讲解 + 代码实现 + 结果解读'的方式,手把手教你用 Python 实现肘部法则和轮廓系数可视化,核心亮点如下:
- 代码精简高效:核心逻辑仅 200 余行,支持模拟数据与真实数据,可直接复用;
- 可视化丰富:包含 4 类图表(肘部曲线、轮廓系数曲线、样本轮廓图、聚类效果图),直观呈现 K 值选择过程;
- 实用性强:解决 K-Means 聚类中最关键的'最优 K 值确定'问题,提供避坑指南与进阶扩展方案。
该方法适用于数据分析、机器学习、数据挖掘等场景,无论你是新手还是有经验的开发者,都能通过本文快速掌握 K 值选择的核心技巧。按照本文步骤操作,即可轻松实现聚类分析中的最优 K 值选择与效果可视化。
微信扫一扫,关注极客日志
微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具
- 加密/解密文本
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
- RSA密钥对生成器
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
- Mermaid 预览与可视化编辑
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
- curl 转代码
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
- Base64 文件转换器
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online