@[toc] K-means 聚类算法 “深入浅出”
n_clustersinitn_initmax_itertolrandom_statealgorithmverbosecopy_xn_jobs(旧版本参数)K 在使用K-means 聚类算法前,确实最关键的一环是确定合理的簇数K。选得太少会“合并不同群体”,选得太多又会“过度细分”。
Python 示例(Elbow + Silhouette 双验证)
K-means 是一种常见的无监督学习算法(Unsupervised Learning),用于将数据自动分成 K 个簇(clusters)。它的目标是让同一簇内的数据尽可能相似,而不同簇之间的数据尽可能不同。
通俗点说:想象你在一个班里想把学生按照“学习风格”分组。你不知道谁学得好谁学得差,只知道他们的考试分数、作业时间等数据。K-means 就帮你自动找出相似的学生,把他们分成几组。
K-means 的过程可以分为 4 步:
设: 数据集为 X = \{x_1, x_2, ..., x_n\},每个样本 x_i \in \mathbb{R}^d 要分成 K 个簇 C_1, C_2, ..., C_K 每个簇的中心为 \mu_k
K-means 的目标函数是最小化簇内平方误差 (SSE): J = \sum_{k=1}^{K} \sum_{x_i \in C_k} ||x_i - \mu_k||^2 也就是说,K-means 想让每个点尽量靠近自己的中心点。
场景: 一家电商公司有用户的购买数据(如下):
| 用户 | 月消费额(元) | 每月购物次数 |
|---|---|---|
| A | 500 | 2 |
| B | 1200 | 6 |
| C | 300 | 1 |
| D | 1000 | 5 |
| E | 4000 | 15 |
| F | 3800 | 14 |
我们想把这些客户分成几类,方便做营销。
最后,算法自动将客户分成两类:
| 客户类型 | 平均月消费 | 平均购物次数 | 营销策略 |
|---|---|---|---|
| 普通客户 | 750元 | 3.5次 | 打折促销、积分奖励 |
| 高价值客户 | 3900元 | 14.5次 | 专属服务、优惠券 |
3900元
14.5次
VIP 客服、专属优惠
优点:
缺点:
from sklearn.cluster import KMeans
import pandas as pd
# 构建数据
data = pd.DataFrame({
'消费额': [500, 1200, 300, 1000, 4000, 3800],
'购物次数': [2, 6, 1, 5, 15, 14]
})
# 训练 K-means 模型
kmeans = KMeans(n_clusters=2, random_state=42)
data['类别'] = kmeans.fit_predict(data)
print(data)
print("簇中心:\n", kmeans.cluster_centers_)
输出结果将展示每个客户属于哪一类,以及各组的中心。
n_clusters
含义:要划分的簇的数量 K。
8init
含义:初始化簇中心的方法。
'k-means++'(默认):通过概率分布方式挑选初始点,能提高稳定性;'random':随机选择初始点;也可直接传入一个自定义初始中心矩阵。'k-means++'。n_init
含义:算法会用不同初始点运行多少次,选择效果最好的结果。
'auto'(通常相当于 10)10~20),可以提高稳定性,减少陷入局部最优的风险。max_iter
含义:每次运行的最大迭代次数。
300tol
含义:容差(收敛阈值),当簇中心变化小于此值时停止迭代。
1e-4random_state
含义:随机种子,确保结果可复现。
random_state=42。algorithm
含义:选择具体的底层算法。
'lloyd'(默认):传统的 Lloyd 算法;'elkan':使用三角不等式加速(只适用于欧氏距离);'auto':根据数据自动选择;'full'(旧版本别名,等价于 'lloyd')。'lloyd' 即可;高维或稀疏数据可试 'elkan'。verbose
含义:是否输出详细日志。
copy_x
含义:是否复制输入数据。
TrueFalse,原数据可能被算法修改,节省内存但需谨慎。n_jobs(旧版本参数)
joblib 自动管理)。from sklearn.cluster import KMeans
import pandas as pd
# 模拟数据
data = pd.DataFrame({
'消费额': [500, 1200, 300, 1000, 4000, 3800],
'购物次数': [2, 6, 1, 5, 15, 14]
})
# 初始化模型
kmeans = KMeans(
n_clusters=2, # 分两类
init='k-means++', # 启发式初始化
n_init=10, # 运行10次取最优
max_iter=300, # 每次最多迭代300次
tol=1e-4, # 收敛阈值
random_state=42, # 固定随机种子
algorithm='lloyd' # 使用经典算法
)
# 拟合模型
kmeans.fit(data)
print("簇中心:\n", kmeans.cluster_centers_)
print("标签:", kmeans.labels_)
调优目标:
n_inittol,增大 max_itern_clusters
加快计算速度
使用
algorithm='elkan'
(仅限欧氏距离)
结果可重现
设置
random_state
K
在使用 K-means 聚类算法前,确实最关键的一步是确定合理的簇数 K。选得太少会“合并不同群体”,选得太多又会“过度分割”。
???? 一、肘部法(Elbow Method)
原理
对不同的 K 值(例如 1~10)运行 K-means;
记录每次的 SSE(Sum of Squared Errors,簇内误差平方和);
画出 “K - SSE” 曲线。
随着 K 的增加,SSE 会持续下降,但下降速度会逐渐放缓。
当下降趋势明显减缓、形成“肘部”时,该点对应的 K 即为较优选择。
优点
简单直观;
适合初步判断簇数。
缺点
肘部位置有时不明显(主观性强);
对高维数据可能效果较差。
???? 二、轮廓系数法(Silhouette Coefficient)
原理
每个样本都有一个轮廓系数 s_i,衡量它与本簇和其他簇的相对紧密度:
s_i = \frac{b_i - a_i}{\max(a_i, b_i)}
其中:
a_i:样本与本簇内其他样本的平均距离;
b_i:样本与最近邻簇中样本的平均距离。
整体平均轮廓系数 S 的取值范围为 [-1, 1],越接近 1 表示聚类效果越好。
实践步骤
对不同 K 值计算平均 Silhouette Score;
取最大值对应的 K。
优点
自动量化聚类质量;
不依赖主观视觉判断。
缺点
计算开销略大;
对形状复杂的簇不总是可靠。
???? 三、Gap Statistic 法(间隙统计)
原理
将真实数据的聚类结果与随机均匀分布数据的聚类结果作比较:
Gap(K) = E^*[\log(W_k)] - \log(W_k)
其中 W_k 是簇内平方和。
当 Gap 值首次显著下降时,对应的 K 为理想值。
优点
理论基础较强;
自动评估“与随机数据相比是否显著更好”。
缺点
计算较慢;
实现复杂(需重复采样)。
???? 四、领域知识 + 可解释性
在商业、工程、金融等应用中,往往可以根据业务逻辑辅助判断 K:
客户类型(普通、高端、VIP) → K=3;
用户地域(东部、西部、北部) → K=3;
产品系列分类 → 固定 K。
算法可提供参考,但最终还要结合领域理解。
???? 五、综合策略推荐
场景
建议方法
数据较简单、初次尝试
肘部法
想客观度量聚类效果
轮廓系数法
数据复杂、需要严格比较
Gap Statistic
有业务逻辑或先验分类
结合领域知识设定 K
???? Python 示例(Elbow + Silhouette 双验证)
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
import matplotlib.pyplot as plt
inertias = []
sil_scores = []
K_range = range(2, 10)
for k in K_range:
kmeans = KMeans(n_clusters=k, random_state=42).fit(X)
inertias.append(kmeans.inertia_)
sil_scores.append(silhouette_score(X, kmeans.labels_))
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
ax1.plot(K_range, inertias, 'o-', label='Inertia')
ax2.plot(K_range, sil_scores, 's--', color='orange', label='Silhouette Score')
ax1.set_xlabel('K')
ax1.set_ylabel('Inertia')
ax2.set_ylabel('Silhouette Score')
plt.title('Elbow & Silhouette Method')
plt.show()
扫码加好友,拉您进群



收藏
