4、寻找标记基因(FindAllMarkers)

聚类分完了,细胞群也有了。然后呢?

你得知道每个簇里到底有什么基因在“撑场面”。说白了,就是找到每个cluster相对于其他细胞高表达的特征基因。Seurat 里做这个事儿的函数叫 FindAllMarkers。

我个人特别喜欢把这步比作“给每个细胞群写身份证”。你的后续细胞类型注释、差异热图绘制,全靠这份身份证列表。弄不好,后面全白搭。

为什么不用手动跑差异?

FindAllMarkers 本质上是把每个簇跟剩下所有细胞做一次差异表达分析。你想想看,如果手动写循环,十几二十个簇,代码又臭又长,还容易漏参数。Seurat 帮你一把梭,返回一个干净的数据框,直接拿来用。

我在项目里遇到过那种“每个簇只找10个基因”的粗暴做法,结果注释出来好几个簇都写成“T细胞”。嗯,后来我学乖了,老老实实用默认参数先扫一遍,再调阈值。

核心用法

假设你已经有了一个处理好的 Seurat 对象,叫 seu,并且 seu$seurat_clusters 已经设好。跑下面这句就行:

markers <- FindAllMarkers(seu, only.pos = TRUE, logfc.threshold = 0.25, min.pct = 0.1)

参数不多,但每个都挺关键。我来拆开说。

参数详解(这张表我经常贴在工位上)

参数默认值说明
only.posFALSE设为 TRUE 只返回在每个簇中上调的基因。我 99% 的情况都开,因为标记基因就是要找高表达的,下调的对于细胞注释没意义。
logfc.threshold0.25平均 logFC 的绝对值门槛。太小会混入大量噪声,太大又可能漏掉一些弱但特异的标记。0.25 是官方推荐,我一般在 0.25~0.5 之间试。
min.pct0.1基因在簇内和簇外的最小表达比例。0.1 比较宽松,如果你数据量大或者想严格点,可以提到 0.25。
test.use"wilcox"差异检验方法。Wilcoxon 秩和检验又快又稳。我有时候会用 MAST 或 DESeq2,但跑几十万细胞时 Wilcox 是首选。
assay默认当前 assay指定哪个 assay 的数据。一般是 "RNA",如果你用了 SCT 标准化,记得切成 "SCT"。
小技巧: 如果你不知道设多少阈值合适,先跑一遍不加过滤(logfc.threshold = 0, min.pct = 0)看输出的 logFC 和 pct 分布,再决定切点。这招我在一个 10x 数据上用过,发现大部分基因 logFC 在 0.1~0.3,于是把阈值设成 0.3 刚刚好。

返回结果长什么样?

跑完后 markers 是一个 data.frame,每行一个基因-簇对。列名如下:

  • p_val — 原始 p-value。
  • avg_log2FC — 该簇相对于其他细胞的平均 log2 倍变化。
  • pct.1 — 该簇内表达该基因的细胞比例。
  • pct.2 — 其他簇中表达该基因的细胞比例。
  • p_val_adj — 多重假设检验校正后的 p-value。看这个!假的看 raw p 会哭。
  • cluster — 所属的簇编号。
  • gene — 基因符号。

注意:avg_log2FC 在 Seurat v5 里改叫 avg_log2FC,老版本可能叫 avg_logFC。这坑我踩过,脚本跑着跑着报错找不到列名,后来发现版本问题。

我曾经历过…… 有一次我图省事,直接用 raw p-value 排序挑前 10 个基因做热图。结果簇 5 和簇 6 的标记基因完全重叠,注释根本分不开。后来发现是 p_val_adj 没控制,假阳性太多。从那以后我只看 p_val_adj < 0.05 的结果。

筛选优质标记的常用套路

拿到 markers 后,我一般这样过滤:

top_markers <- markers %>%
  filter(p_val_adj < 0.05) %>%
  group_by(cluster) %>%
  slice_max(n = 10, order_by = avg_log2FC)

每个簇取 logFC 最高的 10 个基因,同时保证校正显著。这种列表画热图时横轴不会太长,也够你做初步注释。

流程图:从 Seurat 对象到标记基因列表

下面这张图展示了整个 FindAllMarkers 的数据流。我习惯把它放在实验记录本的第一页,提醒自己每一步的意义。

FindAllMarkers 数据流 Seurat 对象 含 seurat_clusters 和归一化数据 传入 FindAllMarkers() 默认 Wilcoxon 检验 参数门槛 logFC & min.pct & p_val_adj 每个簇的 top 基因 按 avg_log2FC 排序 标记列表 用于热图 / 注释 ⬅️ 注意:only.pos=TRUE 只保留上调基因;p_val_adj 必须显著,否则假阳性会污染热图

避坑指南(用钱换来的教训)

  • 千万别忘了 only.pos=TRUE。默认是 FALSE,会给出双向的基因,结果里一半是下调的,画热图时颜色倒过来很别扭。我有个同事就是没设,被老板追问“为什么这个标记基因在所有簇里都低表达?” 尴尬。
  • 大数据集跑得慢? 几十万细胞时 Wilcox 检验也很慢。可以试试 test.use = "poisson" 或者先在 FindAllMarkers 里增加 max.cells.per.ident = 500 参数,只采样 500 个细胞做差异,精度损失不大但速度快 10 倍。
  • 结果行数爆炸。如果不设阈值,一个 20 簇的数据可能输出几十万行。你筛选的时候记得先把 p_val_adj 过滤掉,否则内存撑不住。
一句话总结: FindAllMarkers 是你从无监督聚类走向有监督注释的桥梁。参数调得好,热图画得早;参数调得糙,注释两行泪。