📑 本页目录(点开跳转)
06 · 无监督:聚类与降维
⏱ 28 分钟 | 🎁 可以跳,但降维那半节很有用
🎯 一句话
没有标签的时候,你只能问两个问题:「哪些样本像?」(聚类)和 「能不能用更少的维度表示它?」(降维)。
⚠️ 先说一件最重要的事:无监督没有"正确答案"
监督学习:有标签 → 有准确率 → 【客观】知道好不好
无监督: 没标签 → 没有"对"的分法
你把用户分成 3 类还是 5 类,都不能说谁错
⭐ 所以无监督的评估必须靠【外部标准】:
· 这个分群在业务上讲得通吗?
· 用它做出的下游决策有没有效果?
· 换个随机种子结论还成立吗?
🔑 这是无监督最大的陷阱:算法永远会给你一个结果, 但"算法跑出来了"和"这个分法有意义"是两码事。 轮廓系数只能告诉你"簇分得紧不紧",不能告诉你"这个分法有没有用"。
🎯 一、K-Means:最常用的聚类
① 随机撒 K 个中心点
② 每个样本归到最近的中心
③ 每个中心移到自己那群样本的重心
④ 回到 ②,直到不再变化
○ ○ × ○ ○ ×
○ ○ ○ → ○ ○ ○ → 收敛
× ○ ○ × ○ ○
五个必须知道的坑:
| 坑 | 说明 | 解法 |
|---|---|---|
| K 要自己定 | 算法不会告诉你该分几类 | 肘部法则、轮廓系数、业务意义 ⭐ |
| 必须标准化 | 它用欧氏距离,尺度大的特征会主导 | 先 StandardScaler |
| 只能找"球形"簇 | 长条形、环形的簇它分不好 | 换 DBSCAN / 谱聚类 |
| 初始化敏感 | 不同起点得到不同结果 | n_init=10(跑 10 次取最好)⭐ |
| 对离群点敏感 | 一个极端点能把整个中心拽跑 | 先清离群点,或用 K-Medoids |
🔗 数学原理第 13 章会告诉你: K-Means 是高斯混合模型(GMM)的一个特例—— 它隐含假设了"所有簇都是同样大小的球"。 "只能找球形簇"不是工程缺陷,是这个假设的必然结果。
⭐ 上面这四步用 numpy 写出来只要 12 行:🔗 附录 C 第 8 题。 值得专门去一趟,是因为它补了一个「照着四步写」一定会漏的分支:空簇。 某一轮没有任何点归到某个中心时,
X[lab==j].mean(0)对空数组求均值返回nan, 下一轮所有距离全变nan,算法静默地烂掉——不报错,只是结果不对。 那边还把「⑤n_init=10」这个坑写成了代码(跑 10 次取惯性最小的那次)。
怎么选 K:
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
for k in range(2, 8):
km = KMeans(n_clusters=k, n_init=10, random_state=0).fit(X_scaled)
print(f"K={k} 惯性={km.inertia_:.0f} "
f"轮廓系数={silhouette_score(X_scaled, km.labels_):.3f}")
# 惯性(inertia):簇内平方和,一定随 K 单调下降 → 看【拐点】不是看最小值 ⭐
# 轮廓系数:-1~1,越接近 1 越好;接近 0 说明簇之间黏在一起;负数说明分错了
⚠️ 肘部法则的真相:很多真实数据根本没有明显的肘部,曲线是平滑下降的。 这时候别硬找拐点——改用业务约束("运营团队最多能维护 5 个人群包"就是最好的 K)。
其他聚类算法:
| 算法 | 特点 | 什么时候用 |
|---|---|---|
| DBSCAN | 按密度聚类,不用指定 K,能识别噪声点,能找任意形状 ⭐ | 簇形状不规则、有明显噪声 |
| 层次聚类 | 产出树状图,能看到不同粒度的分组 | 想看层级结构,数据量小(O(n²)) |
| 高斯混合 GMM | 软分配(一个点可以 70% 属于 A、30% 属于 B) | 需要概率、簇是椭圆形 |
🔧 DBSCAN 的两个参数怎么定(想用再点)
eps :多近算"邻居"
min_samples:一个点周围要有几个邻居才算"核心点"
⭐ 定 min_samples:一般取 2×维度
⭐ 定 eps:画 k-距离图(k = min_samples)
对每个点算它到第 k 近邻的距离,排序后画出来
→ 曲线的【拐点】就是 eps
from sklearn.neighbors import NearestNeighbors
import numpy as np, matplotlib.pyplot as plt
k = 2 * X_scaled.shape[1]
d, _ = NearestNeighbors(n_neighbors=k).fit(X_scaled).kneighbors(X_scaled)
plt.plot(np.sort(d[:, -1])) # ⭐ 看拐点
⚠️ DBSCAN 在高维上会失效——密度的概念在高维失去意义 (🔗 数学原理第 5 章 维度灾难)。 超过 10~20 维时先降维。
📉 二、PCA:降维的默认选择
它在做什么:找到数据方差最大的几个方向,把数据投影上去。
原始 2D 数据(沿对角线分布) PCA 后
╱ ────────►
╱ ● ● ● ● ● ●
╱● ● ● → (只保留主方向,
╱ ● ● 垂直方向的信息丢掉)
╱
主成分1 = 方差最大的方向
主成分2 = 与1垂直、方差次大的方向
💡 人话:把一个立体物体投影到最能看清它形状的那个角度。丢掉的是"最不重要"的变化。
💡 为什么"方差大"就是"信息多":
一个特征如果所有样本上都一样(方差为 0),它没有区分任何东西,删掉不损失信息。 方差越大 → 样本在这个方向上差异越大 → 这个方向越能区分样本。 ⚠️ 但注意:"能区分样本" ≠ "能区分标签" —— 这是 PCA 最大的局限,见下。
from sklearn.decomposition import PCA
import numpy as np
pca = PCA().fit(X_scaled)
cum = np.cumsum(pca.explained_variance_ratio_)
print(f"保留 90% 方差需要 {np.argmax(cum >= 0.90) + 1} 个主成分"
f"(原本 {X.shape[1]} 个)")
X_reduced = PCA(n_components=0.95).fit_transform(X_scaled) # 直接指定保留比例
用途:
| 用途 | 说明 |
|---|---|
| 加速训练 | 30 维压到 10 维,训练快 3 倍 |
| 去噪 | 丢掉的小方差方向往往是噪声 |
| 可视化 | 降到 2 维画图看数据分布 |
| 解决共线性 | 主成分之间天然正交 |
| 向量检索加速 | 推荐/搜索里降维后再建索引 |
⚠️ PCA 的四个注意:
- 必须先标准化(否则量纲大的特征会主导主方向)—— 一个"年收入(万元)"和"年龄"放一起,不标准化的话 PC1 基本就是收入
- 主成分没有可解释性(PC1 是一堆原特征的加权和,说不清是什么)
- 它是无监督的——方差大 ≠ 对预测有用。有时候降维反而掉分 ⭐
- ⚠️ 必须在训练集上 fit,再 transform 验证集 —— 在全量数据上 fit 是数据泄漏
# ❌ 泄漏:PCA 看到了验证集的分布
X_all = PCA(n_components=10).fit_transform(X)
tr, va = split(X_all)
# ✅ 正确:放进 Pipeline,CV 自动帮你处理
from sklearn.pipeline import make_pipeline
pipe = make_pipeline(StandardScaler(), PCA(n_components=10), LogisticRegression())
🔗 第 5 章那个纯噪声数据也能跑出 76.5% 准确率的泄漏实验, 就是这类错误的后果。PCA 是最容易泄漏的预处理之一,因为它看起来"只是转换"。
💡 关于第 3 点:有监督的替代品
PCA:找【方差最大】的方向 ← 不看标签
LDA:找【最能分开类别】的方向 ← 看标签 ⭐
→ 如果你的目标是分类,LDA 常常比 PCA 更有用
→ 但 LDA 最多只能降到 (类别数 − 1) 维
🎨 三、t-SNE / UMAP:只用来看图
PCA:线性投影,保留【全局结构】,可以用来做特征
t-SNE/UMAP:非线性,保留【局部邻域】,图好看
⚠️ 但是:
· 它们的坐标轴【没有意义】
· 簇之间的【距离没有意义】
· 簇的【大小没有意义】
· 换个随机种子图就变
🔑 一句话:t-SNE/UMAP 只用来"看一眼数据有没有结构",绝不能拿降维结果当特征喂给模型,也不能用它的图下结论。 UMAP 比 t-SNE 快、更保留全局结构,现在更常用。
⚠️ t-SNE 的 perplexity 参数会显著改变图形:
perplexity 小(5) → 碎成很多小簇(可能是假的)
perplexity 大(50) → 融成大团
⭐ 正确用法:跑 3~4 个不同的 perplexity,
【只相信在所有设置下都稳定出现的结构】
💡 一个可以做的自检:把标签打乱,重跑 t-SNE。 如果打乱后的图看起来还是"有几个漂亮的簇"——说明那些簇是算法造出来的,不是数据里的。
🧭 三种降维怎么选
| 你的目的 | 用什么 |
|---|---|
| 压缩特征喂给模型 | PCA(放 Pipeline 里) |
| 分类任务的有监督降维 | LDA |
| 只是想看一眼数据结构 | UMAP(画图,不当特征) |
| 稀疏矩阵(文本 TF-IDF) | TruncatedSVD(PCA 要中心化会破坏稀疏性)⭐ |
| 有类别特征的高维数据 | Embedding(第 16 章) |
🔗 和站内其他章的关系
| 相关的地方 | 这里的对应 |
|---|---|
| 推荐算法的 Embedding | 也是一种降维——把高维 one-hot 压成低维稠密向量 |
| 推荐算法第 10 章向量检索 | 检索前常用 PCA 降维加速 |
| 数学原理第 13 章 | K-Means 是 GMM 的特例——解释了球形簇的限制 ⭐ |
| 数学原理第 5 章 | 为什么高维上距离和密度都失效 |
| 第 5 章的数据泄漏 | PCA 必须在 Pipeline 里 fit |
| Kaggle 第 1 章 | 竞赛里 PCA/SVD 常作为特征构造手段 |
| 全景导论第 10 章的 CLIP | 对比学习也是无监督的一种 |
⚖️ 要不要深挖这一章
说实话:这一章是本教程里最能跳的。
| 你的情况 | 建议 |
|---|---|
| 做监督学习为主(分类/回归/推荐) | 🟡 知道 PCA 和 K-Means 存在即可 |
| 做用户分群 / 数据探索 | ✅ 聚类那半节要学 |
| 特征太多想压缩 | ✅ PCA 那半节要学 |
| 想快速看数据有没有结构 | ✅ 学会用 UMAP 画图 |
✅ 检查点
- 无监督最大的陷阱是什么?该靠什么评估?
- K-Means 的五个坑是什么?
- 为什么 K-Means 只能找球形簇?(说出根本原因)
- 肘部法则找不到拐点怎么办?
- 为什么"方差大"约等于"信息多"?这个逻辑在什么时候会失效?
- PCA 为什么必须放进 Pipeline?不放会怎样?
- 什么时候该用 LDA 而不是 PCA?
- t-SNE 的 perplexity 该怎么用?怎么自检簇是不是假的?
- 稀疏矩阵为什么该用 TruncatedSVD 而不是 PCA?
👀 答案
- 算法永远会给你结果,但"跑出来了"≠"有意义"。必须靠外部标准评估:业务上讲不讲得通、下游决策有没有效果、换种子结论还成不成立。
- K 要自己定、必须标准化、只能找球形簇、初始化敏感(
n_init=10)、对离群点敏感。 - 因为 K-Means 是 GMM 的特例,隐含假设所有簇都是同样大小的球形高斯。这是假设的必然结果,不是工程缺陷。
- 很多真实数据根本没有明显肘部。这时改用业务约束(如"运营最多维护 5 个人群包")。
- 方差为 0 的特征不区分任何样本,删掉不损失信息;方差越大越能区分样本。失效场景:能区分样本 ≠ 能区分标签——PCA 是无监督的,方差大的方向可能对预测毫无用处。
- 因为在全量数据上 fit 会让 PCA 看到验证集的分布 → 数据泄漏,评估结果虚高。
- 目标是分类时。LDA 找"最能分开类别"的方向(看标签),PCA 只找方差最大(不看标签)。但 LDA 最多降到 (类别数−1) 维。
- 跑 3~4 个不同 perplexity,只相信在所有设置下都稳定出现的结构。自检:把标签打乱重跑,如果还是有漂亮的簇,说明那些簇是算法造的。
- PCA 要中心化(减均值),会把稀疏矩阵变稠密,内存爆炸。TruncatedSVD 不中心化,保持稀疏。
🛑 可以停在这里
⚡ 走神救援
无监督问两个问题:哪些样本像(聚类)、能否用更少维度表示(降维)。⚠️ 最大陷阱:算法永远给结果,但"跑出来了"≠"有意义"——必须靠业务/下游效果评估。K-Means五坑:K要自己定、必须标准化、只能找球形簇(根因:它是GMM的特例,隐含假设等大球形)、初始化敏感(n_init=10)、离群点敏感。肘部常常根本不存在 → 改用业务约束定K。PCA找方差最大方向(方差大=能区分样本,但≠能区分标签,这是它最大局限 → 分类任务考虑 LDA);⚠️ 必须放 Pipeline 里 fit,否则泄漏;稀疏矩阵用 TruncatedSVD(PCA 要中心化会破坏稀疏)。t-SNE/UMAP只能用来看图——坐标轴、簇间距离、簇大小全无意义;perplexity 要跑多个只信稳定出现的结构;把标签打乱重跑还有漂亮簇 = 簇是假的。本章是最能跳的一章。
下一节 👉 07-从线性到神经网络.md