📊 第8章 机器学习 Scikit-Learn
📄 一句话概括

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 秒实验

  1. 把半月形的 n_clusters 改成 4,看轮廓系数和兰德指数是不是都变差。
  2. 把 noise 从 0.08 加到 0.25,看两个指标怎么走。
  3. 想一想:轮廓系数高,但兰德指数低,这种情形该怎么解释?

常见误区

  1. 用调整兰德指数评价真实数据:它要真实标签,真实项目里没有。
  2. 只看 inertia 选 k:它单调下降,没有下限。
  3. 以为轮廓系数高就一定分对了:半月形那次 0.4864 看着还行,实际乱成一团。
  4. 拿 KMeans 硬啃任何形状:它只会画直线边界,弯的形状要换算法。
自测三问(点开对答案) 1. make_blobs 的 cluster_std 控制什么? —— 团内数据的标准差。越大越散,越容易和邻团黏在一起。 2. 轮廓系数的范围是多少,负数意味着什么? —— -1 到 1。负数说明这个点离外人比离自己人还近,可能分错堆了。 3. 为什么选 k 看轮廓系数不看 inertia? —— inertia 加一类必然变小,没有下限;轮廓系数会先升后降,有峰值。

第 8 章到此收尾。第 9 章起是四个真实项目,第一个要连 MySQL 建库,先把数据搬进去。

相关笔记