降维聚类:PCA / UMAP 参数怎么调
跟完这篇,您能把一份标准化后的单细胞数据,从选高变基因、定主成分个数,一路调到聚类分辨率与 UMAP / tSNE 展示,并学会用几张诊断图判断「这套分群到底靠不靠谱」。
降维聚类是单细胞分析的核心一步:把上万维的基因空间压到几十个主成分,再在这个压缩空间里把细胞分成群、摊到二维上看。这一步有四个要自己拿主意的地方——高变基因取多少、主成分留几个、分辨率给多大、UMAP / tSNE 怎么读——本篇逐个讲清每个参数在控制什么、按什么定,最后给一套「合不合理」的自检清单。示例以人类数据、Seurat 较新版本为准;代码片段用于说明每步「做什么、调什么」,不追求可直接整段运行。
这一步在整条流程里的位置
降维聚类不是孤立的一步,它前面必须先做完标准化,后面才谈得上注释。先把这条小流水线摆出来,您就知道下面每个参数卡在哪个环节:
| 环节 | 关键函数 | 在做什么 | 要调的参数 |
|---|---|---|---|
| 选高变基因 | FindVariableFeatures | 挑出细胞间变化最大的基因 | nfeatures |
| 缩放 | ScaleData | 中心化 + 方差归一,为 PCA 铺路 | (可选)vars.to.regress |
| 线性降维 | RunPCA | 压到几十个主成分 | —— |
| 定维度 | ElbowPlot | 看留几个主成分够用 | 后续的 dims |
| 建图聚类 | FindNeighbors / FindClusters | 建近邻图、把细胞分群 | dims、resolution |
| 非线性降维 | RunUMAP / RunTSNE | 把结果摊到二维看 | n.neighbors、min.dist、perplexity |
一句话记住上下游的因果:高变基因和主成分个数决定「聚类在什么空间里做」,分辨率决定「分多细」,UMAP / tSNE 只负责把结果画出来、不参与分群计算。搞混这三层,调参就会无从下手。
第一步:选高变基因
两万多个基因里,大部分在细胞之间几乎不变,留着只会稀释信号、拖慢计算。高变基因(highly variable genes,HVG)就是把「细胞间变化最大」的那批基因挑出来,后续降维只用它们。
Seurat 的标准做法是 vst 方法:先拟合每个基因「均值—方差」的关系,把方差标准化到同一尺度,再按标准化后的方差排序取前若干个。
library(Seurat)
# selection.method = "vst" 是常用默认;nfeatures 决定取多少个高变基因
seu <- FindVariableFeatures(seu, selection.method = "vst", nfeatures = 2000)
# 画出来看看:高变基因(红点)是否落在方差—均值关系的上方
top10 <- head(VariableFeatures(seu), 10)
p <- VariableFeaturePlot(seu)
LabelPoints(plot = p, points = top10, repel = TRUE)
几个要点:
nfeatures = 2000是常用默认,不是铁律。 细胞类型差异明显、异质性高的数据,可以调到 3000;只想分几个大群、或细胞很同质,2000 甚至更少就够。取值在一个范围内变动时,主流群体的结构通常很稳,不必纠结精确数字。- 留意「高变但没生物学意义」的基因。 线粒体基因、核糖体基因、应激基因,以及免疫组库里高度可变的 TCR / BCR 基因,都可能因技术或个体差异冲进高变列表,把聚类带偏成「按批次分」而不是「按细胞类型分」。若发现某群是被这类基因定义的,可在挑选时把它们排除。
- 另一条路线是
SCTransform。 它把标准化、找高变基因、缩放三步合成一步,对技术噪声处理更稳,默认取 3000 个高变基因。用了它就不必再单独跑FindVariableFeatures和ScaleData。两条路线选其一即可,属于常见二选一,没有绝对优劣。
选完高变基因,ScaleData 做中心化和方差归一,PCA 才不会被少数高表达基因主导:
# 只对高变基因缩放即可(默认行为);如需回归掉某些技术因素可加 vars.to.regress
seu <- ScaleData(seu)
第二步:定主成分个数
PCA 把高变基因空间压成一批主成分(PC),前几个 PC 抓住的是细胞间最主要的变异,越往后越接近噪声。降维聚类真正用的不是全部 PC,而是前 N 个——这个 N 是本步要定的关键参数。
seu <- RunPCA(seu)
# 肘图:每个主成分解释的变异(标准差),找拐点
ElbowPlot(seu, ndims = 50)
怎么读肘图:曲线一开始陡降,说明前几个 PC 信息量大;降到某处开始变平,那个「胳膊肘」拐点之后的 PC 增量很小,基本是噪声。取到拐点附近即可,常见落在 10~30 之间,按肘图定、不是固定值。
如果拐点不明显,再补两个判断手段:
-
DimHeatmap看结构。 逐个主成分画热图,能清楚看出前面的 PC 有明显的「一半细胞高、一半细胞低」的分块结构,越往后越糊成一片噪声——糊掉的那些就不用留。DimHeatmap(seu, dims = 1:15, cells = 500, balanced = TRUE) -
宁可略多,不要偏少。 下游聚类对「多留几个 PC」相当稳健,多出来的弱信号影响有限;而留太少会把本该分开的细胞类型压到一起,是更严重的错误。拿不准时,在肘图拐点基础上再多留几个更保险。
| 主成分取太少 | 主成分取太多 |
|---|---|
| 不同细胞类型被压进同一群,分不开 | 引入噪声维度,一般影响不大 |
| 后果重、难察觉 | 后果轻、较稳健 |
| 应尽量避免 | 拿不准时宁可偏这边 |
定好的 N,会作为 dims = 1:N 一路用到后面的建图、聚类和 UMAP,三处保持一致。
第三步:建近邻图、做聚类
聚类分两步:先在前 N 个主成分构成的空间里,给每个细胞找最近的一批邻居、连成图(KNN / SNN 图),再在图上做社区发现,把连得紧的细胞划成一群。
# dims 用第二步定好的主成分个数(这里以 30 为例)
seu <- FindNeighbors(seu, dims = 1:30)
# resolution 越大,分出的 cluster 越多
seu <- FindClusters(seu, resolution = 0.5)
关于 resolution(分辨率),这是全流程里最需要「多试几个值」的参数:
-
它直接控制分群的粗细。 调小,相邻的群会合并、群数变少;调大,一个群会被切成更细的亚群。
-
没有唯一正确的分辨率。 Seurat 官方对几千个细胞的数据常用
0.4~1.2作为起点,这是常用范围、按数据量和目的调:细胞多、想看精细亚型就往大调,只想分几个大类就往小调。 -
用
clustree看分群随分辨率怎么变化。 把多个分辨率的聚类结果串起来看,稳定的真实群体在一段分辨率区间内都稳稳存在,而「过度切分」出来的亚群往往一会儿冒出来、一会儿又并回去,缺乏稳定性。# 先在一串分辨率上各聚一次 seu <- FindClusters(seu, resolution = c(0.2, 0.4, 0.6, 0.8, 1.0)) library(clustree) clustree(seu, prefix = "RNA_snn_res.")prefix要对上聚类结果在meta.data里的列名前缀(用RNAassay 时通常是RNA_snn_res.,用SCTransform则是SCT_snn_res.)。先用colnames(seu@meta.data)核对一下再填。
分辨率的最终定夺,不能只看图好不好看,要结合已知 marker 和生物学预期:分出来的每一群若都能找到可解释的标志基因、对得上预期的细胞类型,这个分辨率就合适;若某些群找不出任何独特 marker,多半是切过头了。
UMAP 与 tSNE 的参数怎么理解
UMAP 和 tSNE 都是非线性降维,作用只有一个——把前 N 个主成分的高维结构摊到二维上,方便肉眼看群。它们都跑在 PCA 空间上、只用于可视化,不参与前一步的聚类计算(聚类早在 FindClusters 就算完了)。
# 两者都吃同样的 dims;换句话说,看到的图是同一套聚类的两种画法
seu <- RunUMAP(seu, dims = 1:30, n.neighbors = 30, min.dist = 0.3)
seu <- RunTSNE(seu, dims = 1:30, perplexity = 30)
DimPlot(seu, reduction = "umap", label = TRUE)
它们各有一两个决定「图长什么样」的参数:
| 参数 | 属于 | 默认(常见值) | 调大会怎样 | 调小会怎样 |
|---|---|---|---|---|
n.neighbors | UMAP | 30 | 更看重全局结构,群间关系更连贯 | 更看重局部,容易碎成小块 |
min.dist | UMAP | 0.3 | 点摊得更开、更松散 | 同群点挤得更紧、团更实 |
perplexity | tSNE | 30 | 每个点参考更多邻居,偏全局 | 偏局部,易出许多小碎团 |
perplexity 可以粗略理解为「tSNE 为每个点考虑的有效邻居数」,一般设在 5~50 之间,且要明显小于细胞总数。这些默认值适用于大多数情况,先用默认跑,图能清楚看出群就不用动。
无论 UMAP 还是 tSNE,有三条底线一定要记住,否则很容易过度解读:
- 群与群之间的距离没有定量意义。 图上两个群离得远,不代表它们在生物学上差异就大;离得近也不代表相似。二维只是一种压缩投影。
- 群的大小、形状也不可当真。 一个群在图上占地大,不代表细胞数多或更重要。
- 换随机种子,图会变。 UMAP / tSNE 有随机性,为了结果可复现,正式出图前固定随机种子(如
set.seed()),并把参数写进方法学。
一句话:UMAP / tSNE 是「看群的放大镜」,不是「量距离的尺子」。 判断细胞类型间关系,要回到 marker 和表达谱,而不是数二维图上的远近。
怎么判断降维聚类是否合理
参数调完,最后要回答一个问题:这套分群是反映了真实的生物学,还是被技术因素带偏了?下面这套自检,逐条过一遍:
-
群是不是被技术变量定义的? 把 UMAP 按线粒体比例、总 UMI 数、样本 / 批次分别上色。如果某一群恰好就是「线粒体特别高的细胞」或「全来自某一个样本」,那它多半是低质量细胞残留或批次效应,而不是真实细胞类型。
FeaturePlot(seu, features = c("percent.mt", "nCount_RNA")) DimPlot(seu, group.by = "orig.ident") # 按样本上色,看是否某群只来自单一样本 -
每群有没有可解释的 marker? 跑
FindAllMarkers,好的分群里每一群都能找出一小批独特、且生物学上讲得通的标志基因。若某群找不出任何特异 marker,通常是切过头的假群。 -
换个主成分个数还稳不稳? 把
dims上下浮动几个(如 25、30、35)重跑,真实的主群体结构应基本不变。一动就散、就重排的结构,说明对参数太敏感、不可靠。 -
换个分辨率还在不在? 借上一节的
clustree,看目标群在一段分辨率区间内是否稳定存在。 -
警惕「桥」状的中间群。 两个大群之间架着一小撮「过渡态」细胞时,先怀疑是双细胞(两个细胞混进一个液滴,表达谱被平均)冒充的假中间态,而非真的连续分化。双细胞的识别见下面的相关教程。
判断合理与否没有单一数字标准,但方向很清楚:真实的群体,经得起「换参数、换配色、看 marker」的反复检验;一碰就变、找不出 marker、或与某个技术变量高度重合的群,都要回头审视。降维聚类是可以迭代的——发现问题就回到对应参数(高变基因、主成分、分辨率)重来一遍即可。
在平台上跑一遍
上面这套调参与自检,在百沐一下不写代码也能完成:上传标准化后的单细胞对象,用一句话说清意图——例如「帮我做降维聚类,选合适的主成分个数和分辨率,并检查分群是否被批次带偏」,组学智能体会自动挑高变基因、给出肘图与多分辨率对比,画好 UMAP / tSNE,并把「按线粒体、按样本上色」的诊断图一并列出来让您判断合理性,同时附上可复现的 R 代码。功能说明见 组学智能体使用指南,或直接到 app.baimuyixia.com 传一份数据试跑。
相关
- 单细胞分析全流程 —— 从质控到注释的主线,本篇是其中「降维聚类」一节的展开
- 单细胞质控三指标怎么设阈值 —— 聚类的前置步骤,含双细胞与低质量细胞的处理
- 细胞类型注释 —— 聚类分完群后,怎么给每群贴上细胞类型标签
- 组学智能体使用指南 —— 在平台上零代码跑通降维聚类