make_blobs 造几团正态分布的点,n_samples 点数、cluster_std 团内散度。 轮廓系数不用真实标签,是真实场景里唯一能用的聚类评价。 inertia 一路往下掉,轮廓系数在 k=3 最高——两个指标指向不一样。
上一篇分完堆却不知道怎么评价。这一篇解决评价,顺带把造数据的工具讲清楚。 make_blobs 和 make_moons 都是 sklearn 自带的,练手时非常好用。
一、make_blobs:造几团点
它一次给两样:点坐标 X 和真实标签 y。
四个常用参数:n_samples 点数、centers 几团、cluster_std 团内多散、random_state 种子。
cluster_std 是团内的标准差,越大团越散、越容易和邻团黏在一起。
这次 0.5 时轮廓系数 0.9235,1.0 时 0.8465,2.5 时 0.6267,一路往下掉。
二、轮廓系数怎么算
对每个点算两个数:到本堆其他点的平均距离 a,到最近那一堆的平均距离 b。 然后算 (b 减 a) 除以 max(a, b)。 自己人越近、外人越远,这个数越接近 1。范围是 -1 到 1。
负数说明这个点可能分错堆了——它离外人比离自己人还近。
三、它为什么重要
轮廓系数不用真实标签。这是它最大的价值。 调整兰德指数要用真实标签,真实项目里根本没有。 所以选 k 的时候,轮廓系数是唯一能用的那把尺子。
这次 k 从 2 到 6,轮廓系数在 k=3 最高,正好对上真实的三个团。
四、两个指标打架怎么办
| k | inertia | 轮廓系数 |
|---|---|---|
| 2 | 1650.33 | 0.7036 |
| 3 | 155.68 | 0.8465 |
| 4 | 135.47 | 0.6864 |
| 5 | 115.82 | 0.5127 |
inertia 一路往下掉,从 1650 掉到 115,看着「越来越好」。 轮廓系数却在 k=3 见顶,之后一路往下。两个指标完全相反。 结论:选 k 看轮廓系数,不看 inertia。因为 inertia 加一类必然变小,没有下限。
顺便说一句,inertia 从 1650 跳到 155 那个大拐点,就是「肘部法」要看的拐点。
五、换一种形状试试
两个交错的半月形,硬用 KMeans 分两类。 轮廓系数 0.4864,调整兰德指数只有 0.2607。 KMeans 只会画直线边界,遇到弯的形状就抓瞎。这不是调参能救的。
这种情况要换算法:DBSCAN、谱聚类,或者先降维再聚类。 选算法之前先看数据长什么样。画一张散点图,比调十次参数有用。
六、动手 Demo:聚类数据生成器与评价
先用不同 cluster_std 造三组数据,看轮廓系数怎么变。 再用轮廓系数给不同的 k 打分,最后在半月形上试一次 KMeans。
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs, make_moons
from sklearn.metrics import adjusted_rand_score, silhouette_score
for sd in (0.5, 1.0, 2.5):
Xs, _ys = make_blobs(n_samples=90, centers=3, cluster_std=sd,
random_state=42)
lb = KMeans(n_clusters=3, n_init=10, random_state=42).fit(Xs).labels_
print("cluster_std %-4g 轮廓系数 %.4f" % (sd, silhouette_score(Xs, lb)))
X, y_true = make_blobs(n_samples=90, centers=3, cluster_std=1.0,
random_state=42)
for k in range(2, 7):
km = KMeans(n_clusters=k, n_init=10, random_state=42).fit(X)
print("k=%d inertia %8.2f 轮廓系数 %.4f"
% (k, km.inertia_, silhouette_score(X, km.labels_)))
Xm, ym = make_moons(n_samples=120, noise=0.08, random_state=42)
km2 = KMeans(n_clusters=2, n_init=10, random_state=42).fit(Xm)
print("半月形 轮廓系数 %.4f,调整兰德指数 %.4f"
% (silhouette_score(Xm, km2.labels_),
adjusted_rand_score(ym, km2.labels_)))
实跑输出:
--------------------------------------------------------------------
聚类数据生成器与评价
--------------------------------------------------------------------
① make_blobs:造几团正态分布的点
--------------------------------------------------------------------
make_blobs 一次给两样东西:点坐标 X(90 行 2 列)和真实标签 y。
它造的是「几团各自正态分布的点」,团与团之间分得比较开。
四个常用参数:n_samples 点数、centers 几团、cluster_std 团内多散、random_state 种子。
| cluster_std | 轮廓系数 | 说明 |
|---|---|---|
| 0.5 | 0.9235 | 紧,分得干净 |
| 1 | 0.8465 | 中等 |
| 2.5 | 0.6267 | 散开,边界模糊 |
cluster_std 越大,团和团越容易黏在一起,轮廓系数越低。
! 造数据是为了练手。真数据不会告诉你「一共几团」,这才是聚类的难点。
② 轮廓系数:既看紧不紧,也看远不远
--------------------------------------------------------------------
轮廓系数这次是 0.8465。
算法:对每个点算两个数——到本堆其他点的平均距离 a,到最近那一堆的平均距离 b。
然后算 (b - a) 除以 max(a, b)。自己人越近、外人越远,这个数越接近 1。
范围是 -1 到 1。负数说明这个点可能分错堆了。
! 轮廓系数不用真实标签,所以真实场景里它是唯一能用的评价。这是它的价值所在。
③ 用轮廓系数选 k
--------------------------------------------------------------------
| k | inertia | 轮廓系数 |
|---:|---:|---:|
| 2 | 1650.33 | 0.7036 |
| 3 | 155.68 | 0.8465 |
| 4 | 135.47 | 0.6864 |
| 5 | 115.82 | 0.5127 |
| 6 | 99.57 | 0.3202 |
inertia 一路往下掉,轮廓系数在 k=3 最高。两个指标指向不一样。
选 k 看轮廓系数,不看 inertia——因为 inertia 加一类必然变小,它没有上限。
! 这就是「肘部法」的由来:inertia 曲线会在真值那里拐一个弯,拐点就是 k。
④ 换一种形状试试
--------------------------------------------------------------------
两个交错的半月,硬用 KMeans 分两类。
轮廓系数 0.4864,调整兰德指数 0.2607。
KMeans 只会画直线边界,遇到弯的形状就抓瞎。这不是调参能救的。
这种情况要换算法:DBSCAN、谱聚类、或者先做降维。
! 选算法之前先看数据长什么样。画一张散点图,比调十次参数有用。
⑤ 这一章收尾
--------------------------------------------------------------------
回归、岭回归、SVM、KMeans,四个算法,一个套路:建、fit、predict。
真正花时间的不是调模型,是准备数据和判断结果靠不靠谱。
! 下一步该学的是交叉验证和特征工程——那才是把模型从「能跑」推到「能用」的东西。
make_blobs 返回的是两个东西,Xs, _ys = ... 里的下划线表示「这个标签我不要」。
silhouette_score(X, labels) 只要坐标和标签,不要真实答案。这就是它能用的原因。
半月形那行轮廓系数 0.4864 看着「还行」,但兰德指数只有 0.2607——指标会骗人,得看形状。
30 秒实验
- 把半月形的 n_clusters 改成 4,看轮廓系数和兰德指数是不是都变差。
- 把 noise 从 0.08 加到 0.25,看两个指标怎么走。
- 想一想:轮廓系数高,但兰德指数低,这种情形该怎么解释?
常见误区
- 用调整兰德指数评价真实数据:它要真实标签,真实项目里没有。
- 只看 inertia 选 k:它单调下降,没有下限。
- 以为轮廓系数高就一定分对了:半月形那次 0.4864 看着还行,实际乱成一团。
- 拿 KMeans 硬啃任何形状:它只会画直线边界,弯的形状要换算法。
自测三问(点开对答案)
1. make_blobs 的 cluster_std 控制什么? —— 团内数据的标准差。越大越散,越容易和邻团黏在一起。 2. 轮廓系数的范围是多少,负数意味着什么? —— -1 到 1。负数说明这个点离外人比离自己人还近,可能分错堆了。 3. 为什么选 k 看轮廓系数不看 inertia? —— inertia 加一类必然变小,没有下限;轮廓系数会先升后降,有峰值。第 8 章到此收尾。第 9 章起是四个真实项目,第一个要连 MySQL 建库,先把数据搬进去。
- ☐ (本篇完,下一篇 9.1 项目概述、效果与准备)