第二章 聚类分析基础与无监督学习概念
说实话,很多人一上来就急着敲命令跑聚类,结果出来一堆看不懂的图。为啥?因为没搞明白聚类到底在做什么。我个人习惯是先理清概念再动手,这样哪怕报错也知道从哪查。这一章我们就聊聊无监督学习里的聚类,以及它和Visium空间转录组数据怎么搭上关系。
2.1 无监督学习:没有标签的探索
监督学习就像老师带着做题——给你输入和正确答案,你学会后去预测新题。无监督学习则像是给你一堆散落的照片,没人告诉你谁是谁,只能自己根据相似度分类。聚类就是其中最典型的代表。
我在做单细胞项目时遇到过这种情况:手动标记了上千个细胞类型,结果聚类出来的群和生物学注释对不上。后来才意识到,聚类本身不关心“正确分类”,它只关心数据内在的分布结构。你想想看,这对Visium数据尤为重要——空间位置和基因表达混合在一起,没有先验的“区域标签”。
| 特性 | 监督学习 | 无监督学习 |
|---|---|---|
| 是否需要标签 | 是 | 否 |
| 目标 | 预测/分类 | 发现结构/分组 |
| 典型算法 | 随机森林、SVM、神经网络 | K-means、DBSCAN、层次聚类 |
| Visium中的应用 | (较少,除非有病理标注) | Spot聚类、空间域识别 |
2.2 常用聚类算法:选哪个最顺手?
我们课程里会用到几种算法,我先简单介绍,后续实战再细说参数调优。
K-means
最直观的一种。你告诉它要分几类(K值),它随机挑K个中心,然后迭代优化。速度快,适合大规模数据。但问题也很明显:必须事先指定K,而且对球形分布的数据效果好。Visium的spot通常呈连续过渡,K-means容易把边界硬切。
DBSCAN
基于密度的算法。它不需要你告诉它分几类,只需要设置半径和最少点数。它能自动识别异常点(噪声),对非球形分布适应好。Visium数据中,不同组织区域密度可能差异大——比如肿瘤区spots密集,间质区稀疏——DBSCAN在这种场景下表现不错。
层次聚类
可以理解为建立一棵“聚类树”,你从树的不同高度切开得到不同粒度的分组。优点是结果可以可视化(树状图),而且不需要预设K值。缺点:O(n²)复杂度,spot数较多时(比如一万个以上)内存会炸。我个人只在探索性分析时用,比如抽几百个代表性spot。
2.3 距离度量:聚类的“相似”怎么算?
所有聚类算法都依赖“距离”或“相似度”。你用欧氏距离还是余弦相似度,结果可能完全不同。
- 欧氏距离:最常用,但受量纲影响大。Visium的基因表达矩阵通常先标准化再算。
- 余弦相似度:只看方向,不考虑绝对大小,适合稀疏的高维表达数据。
- 曼哈顿距离:对异常值更鲁棒,偶尔用在空间坐标距离上。
举个例子,计算两个spot的基因表达余弦相似度:
import numpy as np
spot_a = np.array([0.1, 0.8, 0.3, 0.0])
spot_b = np.array([0.2, 0.7, 0.4, 0.1])
cos_sim = np.dot(spot_a, spot_b) / (np.linalg.norm(spot_a) * np.linalg.norm(spot_b))
print(f"余弦相似度: {cos_sim:.3f}")
2.4 怎么知道聚类结果好不好?
无监督学习因为没有真值,评估聚类质量只能靠内部指标。常用的有几个:
| 指标 | 原理 | 推荐值 | 我的使用习惯 |
|---|---|---|---|
| 轮廓系数 | 衡量类内紧凑 vs 类间分离 | 0.25以上 | 首选,直观 |
| Davies-Bouldin指数 | 类间距离/类内距离的均值 | 越低越好 | 配合轮廓系数一起看 |
| Calinski-Harabasz指数 | 类间方差/类内方差的比值 | 越高越好 | 计算快,但偏好在球形簇 |
不过话说回来,内部指标只能作为参考。真正的“好”还要看生物学解释——比如聚类出来的区域是否对应已知的组织结构(皮质层、肿瘤核心等)。我通常先用轮廓系数粗筛几个候选K值,再结合空间分布可视化做最终判断。
2.5 Visium聚类复现的整体流程
下面这张SVG图把从原始数据到聚类结果的关键步骤串起来了。注意看,我们后续Docker部署就是要把这一套流程容器化。
你看,整个流程并不复杂。但难点在于环境一致性——不同的库版本、不同的CUDA版本,稍有不慎结果就不可复现。这就是为什么我们要用Docker把所有依赖打包,跑出来的聚类结果换个机器也能一模一样。