跳到正文
百沐一下百沐一下
本节目录

降维聚类:PCA / UMAP 参数怎么调

跟完这篇,您能把一份标准化后的单细胞数据,从选高变基因、定主成分个数,一路调到聚类分辨率与 UMAP / tSNE 展示,并学会用几张诊断图判断「这套分群到底靠不靠谱」。

降维聚类是单细胞分析的核心一步:把上万维的基因空间压到几十个主成分,再在这个压缩空间里把细胞分成群、摊到二维上看。这一步有四个要自己拿主意的地方——高变基因取多少、主成分留几个、分辨率给多大、UMAP / tSNE 怎么读——本篇逐个讲清每个参数在控制什么、按什么定,最后给一套「合不合理」的自检清单。示例以人类数据、Seurat 较新版本为准;代码片段用于说明每步「做什么、调什么」,不追求可直接整段运行。

这一步在整条流程里的位置

降维聚类不是孤立的一步,它前面必须先做完标准化,后面才谈得上注释。先把这条小流水线摆出来,您就知道下面每个参数卡在哪个环节:

环节关键函数在做什么要调的参数
选高变基因FindVariableFeatures挑出细胞间变化最大的基因nfeatures
缩放ScaleData中心化 + 方差归一,为 PCA 铺路(可选)vars.to.regress
线性降维RunPCA压到几十个主成分——
定维度ElbowPlot看留几个主成分够用后续的 dims
建图聚类FindNeighbors / FindClusters建近邻图、把细胞分群dimsresolution
非线性降维RunUMAP / RunTSNE把结果摊到二维看n.neighborsmin.distperplexity

一句话记住上下游的因果:高变基因和主成分个数决定「聚类在什么空间里做」,分辨率决定「分多细」,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)

几个要点:

  1. nfeatures = 2000 是常用默认,不是铁律。 细胞类型差异明显、异质性高的数据,可以调到 3000;只想分几个大群、或细胞很同质,2000 甚至更少就够。取值在一个范围内变动时,主流群体的结构通常很稳,不必纠结精确数字。
  2. 留意「高变但没生物学意义」的基因。 线粒体基因、核糖体基因、应激基因,以及免疫组库里高度可变的 TCR / BCR 基因,都可能因技术或个体差异冲进高变列表,把聚类带偏成「按批次分」而不是「按细胞类型分」。若发现某群是被这类基因定义的,可在挑选时把它们排除。
  3. 另一条路线是 SCTransform 它把标准化、找高变基因、缩放三步合成一步,对技术噪声处理更稳,默认取 3000 个高变基因。用了它就不必再单独跑 FindVariableFeaturesScaleData。两条路线选其一即可,属于常见二选一,没有绝对优劣。

选完高变基因,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(分辨率),这是全流程里最需要「多试几个值」的参数:

  1. 它直接控制分群的粗细。 调小,相邻的群会合并、群数变少;调大,一个群会被切成更细的亚群。

  2. 没有唯一正确的分辨率。 Seurat 官方对几千个细胞的数据常用 0.4~1.2 作为起点,这是常用范围、按数据量和目的调:细胞多、想看精细亚型就往大调,只想分几个大类就往小调。

  3. 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 里的列名前缀(用 RNA assay 时通常是 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.neighborsUMAP30更看重全局结构,群间关系更连贯更看重局部,容易碎成小块
min.distUMAP0.3点摊得更开、更松散同群点挤得更紧、团更实
perplexitytSNE30每个点参考更多邻居,偏全局偏局部,易出许多小碎团

perplexity 可以粗略理解为「tSNE 为每个点考虑的有效邻居数」,一般设在 5~50 之间,且要明显小于细胞总数。这些默认值适用于大多数情况,先用默认跑,图能清楚看出群就不用动

无论 UMAP 还是 tSNE,有三条底线一定要记住,否则很容易过度解读:

  1. 群与群之间的距离没有定量意义。 图上两个群离得远,不代表它们在生物学上差异就大;离得近也不代表相似。二维只是一种压缩投影。
  2. 群的大小、形状也不可当真。 一个群在图上占地大,不代表细胞数多或更重要。
  3. 换随机种子,图会变。 UMAP / tSNE 有随机性,为了结果可复现,正式出图前固定随机种子(如 set.seed()),并把参数写进方法学。

一句话:UMAP / tSNE 是「看群的放大镜」,不是「量距离的尺子」。 判断细胞类型间关系,要回到 marker 和表达谱,而不是数二维图上的远近。

怎么判断降维聚类是否合理

参数调完,最后要回答一个问题:这套分群是反映了真实的生物学,还是被技术因素带偏了?下面这套自检,逐条过一遍:

  1. 群是不是被技术变量定义的? 把 UMAP 按线粒体比例、总 UMI 数、样本 / 批次分别上色。如果某一群恰好就是「线粒体特别高的细胞」或「全来自某一个样本」,那它多半是低质量细胞残留或批次效应,而不是真实细胞类型。

    FeaturePlot(seu, features = c("percent.mt", "nCount_RNA"))
    DimPlot(seu, group.by = "orig.ident")   # 按样本上色,看是否某群只来自单一样本
    
  2. 每群有没有可解释的 marker?FindAllMarkers,好的分群里每一群都能找出一小批独特、且生物学上讲得通的标志基因。若某群找不出任何特异 marker,通常是切过头的假群。

  3. 换个主成分个数还稳不稳?dims 上下浮动几个(如 25、30、35)重跑,真实的主群体结构应基本不变。一动就散、就重排的结构,说明对参数太敏感、不可靠。

  4. 换个分辨率还在不在? 借上一节的 clustree,看目标群在一段分辨率区间内是否稳定存在。

  5. 警惕「桥」状的中间群。 两个大群之间架着一小撮「过渡态」细胞时,先怀疑是双细胞(两个细胞混进一个液滴,表达谱被平均)冒充的假中间态,而非真的连续分化。双细胞的识别见下面的相关教程。

判断合理与否没有单一数字标准,但方向很清楚:真实的群体,经得起「换参数、换配色、看 marker」的反复检验;一碰就变、找不出 marker、或与某个技术变量高度重合的群,都要回头审视。降维聚类是可以迭代的——发现问题就回到对应参数(高变基因、主成分、分辨率)重来一遍即可。

在平台上跑一遍

上面这套调参与自检,在百沐一下不写代码也能完成:上传标准化后的单细胞对象,用一句话说清意图——例如「帮我做降维聚类,选合适的主成分个数和分辨率,并检查分群是否被批次带偏」,组学智能体会自动挑高变基因、给出肘图与多分辨率对比,画好 UMAP / tSNE,并把「按线粒体、按样本上色」的诊断图一并列出来让您判断合理性,同时附上可复现的 R 代码。功能说明见 组学智能体使用指南,或直接到 app.baimuyixia.com 传一份数据试跑。

相关