CCA 在单细胞中的应用:Seurat 中的 CCA 流程、参数设置、注意事项
CCA,全称 Canonical Correlation Analysis,中文叫典型相关分析。说白了,它是一种衡量两组数据之间“共同变异”的方法。在单细胞领域,我们用它来寻找不同批次之间细胞状态的对应关系。
我记得我第一次用 Seurat 整合数据,面对一堆参数完全懵了。后来慢慢摸索,才明白这玩意儿其实挺直接的。今天咱就聊聊,怎么在 Seurat 里用好 CCA。
Seurat 里 CCA 的核心流程
Seurat 的整合框架,本质是两步:先找锚点,再做整合。CCA 主要负责第一步——找锚点。
大致流程如下:
- 标准化与特征选择:每个样本单独跑 NormalizeData + FindVariableFeatures。
- 跨样本 CCA:用 SelectIntegrationFeatures 选出共享的高变基因,然后 RunCCA 计算典型相关。
- 锚点识别:通过 FindIntegrationAnchors 在 CCA 低维空间里探测“互相最近邻”的细胞对。
- 数据整合:IntegrateData 利用这些锚点,把表达矩阵校正到同一空间。
关键点:你不需要手动调 CCA 的数学细节,Seurat 已经封装好了。但参数踩坑可是家常便饭。
参数设置:这几个值得盯着调
Seurat 的整合函数 FindIntegrationAnchors 和 IntegrateData 里有一堆参数。我挑三个最常出问题的,逐一说说我的踩坑经历。
| 参数 | 默认值 | 作用 | 我的建议 |
|---|---|---|---|
k.anchor |
5 | 每个锚点周围用于计算权重的邻居数 | 样本量小(<5000)时可以用 3-5;大数据(>5万)可以提到 10-20。太小会过拟合,太大容易模糊批次边界。 |
k.filter |
200 | 过滤掉最多匹配锚点数量的上限 | 默认值一般够用。但我遇到过异质性很大的实验设计,比如肿瘤样本和正常样本差异过大,需要把 k.filter 降到 100 左右,否则会引入很多假阳性锚点。 |
k.score |
30 | 计算锚点得分时考虑的邻居数 | 这个参数影响锚点的“可信度筛选”。我习惯保持 30,除非你有明确理由。 |
警告:不要把 k.anchor 设得比 k.filter 大。逻辑上讲不通,程序会报错,但很多人会写反。我自己就犯过这个低级错误,排查了半小时才发现参数顺序错了。
在实际项目中,CCA 的预处理坑
CCA 对输入数据非常敏感。我曾经处理过一个包含 10x v2 和 v3 两个平台的数据,直接丢进 RunCCA,结果整合效果很差。后来发现,两个版本的基因捕获效率不同,导致部分基因的方差分布差异巨大。
应该怎么做?
- 确保数据已经标准化:建议用 SCTransform 代替 LogNormalize,它能更好地处理不同检测深度的批次。
- 特征数量要合理:SelectIntegrationFeatures 默认取 2000 个高变基因。如果你研究的细胞类型非常稀有,可以考虑增加到 3000-5000,否则稀有群体可能被淹没。
- 维度选择:RunCCA 默认只保留 50 个典型相关维度(1:50)。你想想看,如果样本差异特别大,这 50 维可能不够。可以设置
num.cc = 100,但别超过样本内细胞数的 1/10。
避坑指南:我曾经一次性处理 8 个样本,每一对样本都独立跑 CCA,结果内存直接爆表。后来才学会用 SelectIntegrationFeatures + PrepSCTFindMarkers 这种 pipeline,把特征选择和归一化统一处理,效率高多了。
一个简单的代码示例
下面是我常用的一套流程,适用于两个样本的整合。注意配置里的注释:
# 标准化(以 SCTransform 为例)
s1 <- SCTransform(s1, verbose = FALSE)
s2 <- SCTransform(s2, verbose = FALSE)
# 整合特征选择
features <- SelectIntegrationFeatures(object.list = list(s1, s2), nfeatures = 3000)
# 准备锚点
anchors <- FindIntegrationAnchors(
object.list = list(s1, s2),
anchor.features = features,
normalization.method = "SCT",
k.anchor = 10, # 因为两个样本都超过 1 万细胞
k.filter = 150, # 我们担心差异太大,所以降低过滤阈值
k.score = 30,
reduction = "cca", # 明确指定用 CCA
dims = 1:50
)
# 整合
combined <- IntegrateData(anchorset = anchors, normalization.method = "SCT", dims = 1:50)
这段代码跑完后,combined 对象里的整合矩阵就可以直接用来降维和聚类了。
CCA 整合的适用场景与局限
CCA 不是万能的。我自己的经验是,它特别适合以下情况:
- 批次效应表现为主成分旋转差异,而不是单纯的均值偏移。
- 细胞类型在两个批次中都存在,CCA 可以用共享的共变异结构锚定它们。
- 样本量差异不大。如果一个样本只有 500 细胞,另一个有 5 万,CCA 的锚点倾向于集中在数据量大的批次,稀有批次很难配对。
反过来,如果两个批次的细胞组成完全不同(比如你硬把 PBMC 和肿瘤组织整合),CCA 基本没用——它找不到有意义的共同变异。这时候还不如用 MNN 或者 scVI。
SVG 图:CCA 锚点识别与整合逻辑
下面这张图能帮你直观理解 CCA 在 Seurat 里是怎么工作的。
几个需要注意的细节
嗯,这里还要补充几点现场经验:
- 特征数量别贪多:我见过有同学直接选 5000 个基因。说实话,CCA 的奇异值分解速度会成倍增加,而且很多噪音特征会拉低信噪比。2000-3000 足够了。
- 降维范围别死用默认:RunCCA 默认拿前 50 维。但如果你两个样本的细胞类型差异很大,可以试试
dims = 1:30或1:20。选多少合适?跑完 CCA 后画个ElbowPlot看一下。 - 内存使用:整合步骤 IntegrateData 会生成一个很大的矩阵。如果你的机器只有 32GB 内存,处理 10 万个细胞就会很吃力。可以考虑分批次整合,或者用
merge先合并再细调。
一句话总结:CCA 在 Seurat 里就像一个“翻译官”,用共享的基因协方差模式把不同批次拉到一个坐标系。参数调得好,翻译就准;调不好,就是鸡同鸭讲。