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

分类有标签可学,聚类只能看「哪些点离得近」。 KMeans 四步:挑中心、归堆、挪中心、重复,直到中心不动。 分三类时调整兰德指数 1.0000,硬分五类掉到 0.7370。

📝 本章和前面几章的关系

上一篇有 y,模型知道每个点该属于哪一类。这一篇没有 y,只能靠距离。 数据用 make_blobs 造九十个点,真实三类,但训练时假装不知道。

一、和分类的根本区别

分类学的是「什么样的点该分到哪一类」,有标准答案。 聚类没有答案,只能看「哪些点长得像」。判断标准是距离。 所以聚类没有「对不对」,只有「分得合不合用」。这是它最麻烦的地方。

fit 也只接一个 X,没有 y——这是它和前面几个算法最明显的差别。

二、KMeans 的四步

第一步,随便挑 k 个点当中心。 第二步,每个点归到离它最近的中心。 第三步,把每个堆的中心挪到这堆点的平均位置。

第四步,重复二三步,直到中心不再移动。 它一定会停,但不保证停在最好的地方。所以要换几组初始中心各跑一遍。

三、跑一次看看

九十个点分成三类,每类正好 30 个。 三个中心是 (4.652, 2.069)、(-7.066, -6.610)、(-2.709, 8.810)。 inertia 是「每个点到它自己中心的距离平方和」,这次是 155.68。

inertia 越小说明堆越紧。但它是绝对值,不同数据之间没法比。 n_init=10 是「换十组初始中心各跑一遍,取 inertia 最小的」。省了它会不稳。

四、分得准不准

真实标签其实有,刚才只是假装没有。现在拿来对一下。 调整兰德指数 1.0000,说明分得一点不差。 1 是完全一致,0 是跟瞎猜差不多。这个指标已经扣掉了「碰巧对上」的成分。

真实场景里没有真实标签,这个指标根本用不了——所以下一篇讲别的评价办法。

五、分错堆长什么样

硬分成五类,调整兰德指数掉到 0.7370。 k 选错,结果就散。但注意,inertia 反而更小了:五类肯定比三类紧。 所以不能拿 inertia 选 k。分一百类,每类一个点,inertia 直接是 0。

这也是聚类最容易踩的坑:指标越「好」,结果越没用。

六、动手 Demo:聚类:没有标签怎么分堆

造九十个点,真实三类,但训练时只给坐标不给标签。 分完再拿真实标签对照,最后故意分成五类看结果怎么散。

import numpy as np
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
from sklearn.metrics import adjusted_rand_score

X, y_true = make_blobs(n_samples=90, centers=3, cluster_std=1.0,
                       random_state=42)
km = KMeans(n_clusters=3, n_init=10, random_state=42).fit(X)

for c in range(3):
    print("第 %d 类:%d 个点" % (c, int((km.labels_ == c).sum())))
print("inertia %.2f" % km.inertia_)
print("调整兰德指数 %.4f" % adjusted_rand_score(y_true, km.labels_))

km5 = KMeans(n_clusters=5, n_init=10, random_state=42).fit(X)
print("硬分五类:inertia %.2f,调整兰德指数 %.4f"
      % (km5.inertia_, adjusted_rand_score(y_true, km5.labels_)))

print("第一个中心 %s" % np.round(km.cluster_centers_[0], 3).tolist())

实跑输出:

--------------------------------------------------------------------
聚类:没有标签怎么分堆
--------------------------------------------------------------------

  ① 和分类的区别
  --------------------------------------------------------------------
  分类有标签,模型学「什么样的点该分到哪一类」。
  聚类没标签,模型只能自己看「哪些点长得像」。
  判断标准是距离:离得近的归一堆。就这么朴素。
  ! 聚类没有标准答案,所以评价也难。这是它和分类最大的不同。

  ② KMeans 的四步
  --------------------------------------------------------------------
  第一步,随便挑 k 个点当中心。
  第二步,每个点归到最近的中心。
  第三步,把每个堆的中心挪到这堆点的平均位置。
  第四步,重复二三步,直到中心不再移动。
  ! 它一定会停,但不保证停在最好的地方。所以要多试几个初始中心,取最好的。

  ③ 跑一次
  --------------------------------------------------------------------
  九十个点,真实是三类,但我们假装不知道。
  分成三类之后,每类的点数:
    第 0 类 30 个点
    第 1 类 30 个点
    第 2 类 30 个点
  三个中心点:
    [4.652, 2.069]
    [-7.066, -6.61]
    [-2.709, 8.81]
  inertia 是「每个点到它自己中心的距离平方和」,越小越紧。这次是 155.68。
  ! n_init=10 是「换十组初始中心,各跑一遍,取 inertia 最小的」。省了它会不稳。

  ④ 分得准不准
  --------------------------------------------------------------------
  真实标签我们其实有,只是刚才假装没有。现在拿来对一下。
  调整兰德指数 1.0000。
  1 是完全一致,0 是跟瞎猜差不多。这次正好是 1.0000,分得一点不差。
  ! 真实场景里没有真实标签,这个指标用不了。所以聚类评价要靠轮廓系数。

  ⑤ 分错堆长什么样
  --------------------------------------------------------------------
  硬分成五类,调整兰德指数掉到 0.7370。
  k 选错,结果就散。但 inertia 会一直变小——五类肯定比三类紧。
  所以不能拿 inertia 选 k,得用轮廓系数或者肘部法。
  ! 这是聚类最容易踩的坑:以为 inertia 越小越好,结果分出一百类,每类一个点,inertia 是 0。

labels_ 是每个点被分到的类号。类号本身没有含义,0 类不一定是「第一类」。 cluster_centers_ 是算出来的中心坐标,可以拿去解释「这一堆大概长什么样」。 注意五类时 inertia 更小、兰德指数更差,这一对矛盾就是选 k 的难点。

30 秒实验

  1. 把 n_clusters 改成 2 和 4,各跑一次,看调整兰德指数。
  2. 把 n_init 改成 1,连跑五次,看 inertia 是不是每次都一样。
  3. 想一想:真实场景里没有真实标签,你怎么知道分得对不对?

常见误区

  1. 拿 inertia 选 k:加类必然变小,分一百类 inertia 是 0,毫无意义。
  2. 把类号当顺序:0、1、2 只是编号,没有大小和先后。
  3. 忘了 n_init:初始中心随机,跑一次的结果可能很糟。
  4. 以为聚类有标准答案:真实数据里没有,只能说「合不合用」。
自测三问(点开对答案) 1. 聚类和分类最根本的区别? —— 分类有标签可学,聚类只有坐标,靠距离自己分。 2. KMeans 的四步是什么? —— 挑初始中心、按最近归堆、把中心挪到堆的平均位置、重复到中心不动。 3. 为什么不能用 inertia 选 k? —— 类越多每堆越紧,inertia 必然越小,它没有下限。

分完了却不知道怎么评价。下一篇:造数据的生成器,和不用标签的评价指标。

相关笔记