748. 空间转录组细胞解卷积¶
一句话概述:空间转录组每个测量点通常包含多个细胞,解卷积就是推算每个点里各种细胞类型分别占多少比例——就像从一杯混合果汁中分析出苹果汁、橙汁、葡萄汁各占多少。
核心知识点速查表¶
| 概念 | 白话解释 | 关键工具 |
|---|---|---|
| 解卷积 | 从混合信号中分解出各组分的比例 | Cell2location, RCTD |
| Spot | Visium等平台的测量单位(含1-10个细胞) | 10x Visium |
| 参考数据 | 用于训练的单细胞RNA-seq数据 | 同组织scRNA-seq |
| Cell2location | 贝叶斯模型的空间解卷积 | Python/PyTorch |
| RCTD | 稳健的细胞类型解卷积 | R (spacexr) |
| SPOTlight | 基于NMF的解卷积 | R |
| 分辨率 | Visium≈55μm(多细胞), Slide-seq≈10μm(近单细胞) | 平台依赖 |
一、原理(白话版)¶
1.1 为什么需要解卷积?¶
10x Visium等平台:
每个spot直径55μm → 通常包含1-10个细胞
测到的基因表达 = 所有细胞表达的混合
问题:
Spot A的表达谱 = 30% T细胞 + 50% 巨噬细胞 + 20% 成纤维细胞
但我们只看到了混合后的总表达
解卷积就是:
输入:每个spot的混合表达谱 + 参考scRNA-seq(知道各细胞类型的"特征表达")
输出:每个spot中各细胞类型的比例
1.2 主要方法对比¶
| 方法 | 原理 | 优点 | 缺点 |
|---|---|---|---|
| Cell2location | 贝叶斯概率模型 | 准确度高,考虑不确定性 | 慢,需GPU |
| RCTD | 回归模型 | 快,稳健 | 不建模不确定性 |
| SPOTlight | NMF+NNLS | 快,简单 | 精度一般 |
| Tangram | 深度学习映射 | 可用于多模态 | 需要GPU |
二、Cell2location分析流程¶
2.1 安装¶
# 安装cell2location
pip install cell2location # 安装主包(需要PyTorch)
# 如果有GPU
pip install cell2location[gpu]
# 验证
python -c "import cell2location; print(cell2location.__version__)"
2.2 准备数据¶
# ===== 准备输入数据 =====
import scanpy as sc # 导入scanpy
import cell2location # 导入cell2location
import numpy as np
# 1. 加载空间转录组数据
adata_vis = sc.read_visium("visium_output/") # 读取10x Visium数据
adata_vis.var_names_make_unique() # 确保基因名唯一
# 基本质控
sc.pp.filter_genes(adata_vis, min_cells=3) # 至少3个spot表达的基因
adata_vis.var["mt"] = adata_vis.var_names.str.startswith("MT-")
sc.pp.calculate_qc_metrics(adata_vis, qc_vars=["mt"], inplace=True)
# 2. 加载参考scRNA-seq数据
adata_ref = sc.read_h5ad("reference_scrna.h5ad") # 读取参考数据
# 确保adata_ref.obs["cell_type"]列有细胞类型注释
# 过滤参考数据
sc.pp.filter_genes(adata_ref, min_cells=10) # 至少10个细胞表达
# 取交集基因
shared_genes = adata_vis.var_names.intersection(adata_ref.var_names)
adata_vis = adata_vis[:, shared_genes]
adata_ref = adata_ref[:, shared_genes]
print(f"共有基因数: {len(shared_genes)}")
2.3 训练参考模型¶
# ===== 第一步:从scRNA-seq学习细胞类型特征 =====
from cell2location.models import RegressionModel
# 设置模型
RegressionModel.setup_anndata(
adata_ref,
batch_key="sample", # 参考数据的批次(如果有)
labels_key="cell_type" # 细胞类型标签
)
# 创建回归模型
mod_ref = RegressionModel(adata_ref)
# 训练
mod_ref.train(
max_epochs=250, # 最大训练轮数
batch_size=2500, # 批次大小
train_size=1, # 使用全部数据训练
lr=0.002 # 学习率
)
# 查看训练历史
mod_ref.plot_history(20) # 查看最后20个epoch的loss
# 导出每种细胞类型的特征表达谱
adata_ref = mod_ref.export_posterior(
adata_ref,
sample_kwargs={"num_samples": 1000, "batch_size": 2500}
)
# 保存参考特征
ref_sig = adata_ref.varm["means_per_cluster_mu_fg"] # 细胞类型特征矩阵
2.4 空间解卷积¶
# ===== 第二步:在空间数据上做解卷积 =====
from cell2location.models import Cell2location
# 准备空间数据
# 将参考特征添加到空间数据
inf_aver = adata_ref.varm["means_per_cluster_mu_fg"].copy()
adata_vis.uns["mod"] = {"inf_aver": inf_aver}
# 设置Cell2location模型
Cell2location.setup_anndata(
adata_vis,
batch_key=None # Visium数据通常不分批次
)
# 创建模型
mod_vis = Cell2location(
adata_vis,
cell_state_df=inf_aver, # 参考细胞类型特征
N_cells_per_location=10, # 每个spot预期的细胞数
detection_alpha=200 # 检测灵敏度参数
)
# 训练
mod_vis.train(
max_epochs=30000, # 需要更多轮次
batch_size=None, # 使用全部数据
train_size=1,
lr=0.002
)
# 导出结果
adata_vis = mod_vis.export_posterior(
adata_vis,
sample_kwargs={"num_samples": 1000, "batch_size": mod_vis.adata.n_obs}
)
# 每种细胞类型在每个spot中的估计细胞数
# 存储在 adata_vis.obsm["q05_cell_abundance_w_sf"]
cell_counts = adata_vis.obsm["q05_cell_abundance_w_sf"]
print(f"Cell type columns: {cell_counts.columns.tolist()}")
2.5 可视化¶
# ===== 可视化解卷积结果 =====
import matplotlib.pyplot as plt
# 在组织切片上显示各细胞类型的空间分布
cell_types = cell_counts.columns.tolist()
fig, axes = plt.subplots(2, 4, figsize=(20, 10))
axes = axes.flatten()
for i, ct in enumerate(cell_types[:8]): # 显示前8种细胞类型
adata_vis.obs[ct] = cell_counts[ct].values
sc.pl.spatial(
adata_vis,
color=ct,
cmap="Reds",
size=1.3,
ax=axes[i],
show=False,
title=ct
)
plt.tight_layout()
plt.savefig("cell_type_spatial_distribution.png", dpi=300)
plt.show()
# 饼图可视化(每个spot一个饼图显示细胞类型比例)
# 转为比例
cell_proportions = cell_counts.div(cell_counts.sum(axis=1), axis=0)
adata_vis.obsm["cell_proportions"] = cell_proportions
三、RCTD(R语言替代方案)¶
# ===== RCTD解卷积 =====
library(spacexr) # 安装:devtools::install_github("dmcable/spacexr")
library(Seurat)
# 准备参考数据
reference <- Reference(
counts = ref_counts, # 参考scRNA-seq的count矩阵
cell_types = ref_cell_types, # 细胞类型向量
nUMI = ref_nUMI # 每个细胞的UMI总数
)
# 准备空间数据
coords <- data.frame(
x = spatial_coords$x,
y = spatial_coords$y
)
puck <- SpatialRNA(
coords = coords, # 空间坐标
counts = spatial_counts, # 空间count矩阵
nUMI = colSums(spatial_counts) # 每个spot的UMI数
)
# 创建RCTD对象
myRCTD <- create.RCTD(
puck,
reference,
max_cores = 8 # CPU核心数
)
# 运行解卷积
myRCTD <- run_RCTD(
myRCTD,
doublet_mode = "full" # full=允许每个spot多种细胞类型
)
# 提取结果
results <- myRCTD@results
weights <- results$weights # 每个spot中各细胞类型的比例
四、常见报错与解决¶
| 报错信息 | 原因 | 解决方案 |
|---|---|---|
Cell2location: CUDA error | GPU显存不足 | 减少num_samples或用CPU |
Too few shared genes | 参考和空间数据基因不匹配 | 检查基因名格式(symbols vs ensembl) |
Negative cell counts | 模型拟合问题 | 增加训练轮数或调整N_cells_per_location |
RCTD: singular matrix | 参考数据细胞类型太少 | 每种细胞类型至少25个细胞 |
All zeros in spot | 空spot | 过滤UMI<100的spot |
五、面试高频问题¶
Q1: Cell2location和RCTD的区别?¶
A: Cell2location用贝叶斯概率模型,能给出不确定性估计,适合复杂组织;RCTD用回归模型,速度更快,更稳健。如果有GPU且需要高精度用Cell2location,CPU环境或快速分析用RCTD。
Q2: 解卷积需要什么样的参考数据?¶
A: ①同组织/同物种的scRNA-seq数据;②包含所有预期存在的细胞类型;③每种细胞类型至少25-50个细胞;④注释准确(错误注释会传播到解卷积结果)。
Q3: 如何验证解卷积结果?¶
A: ①免疫荧光/免疫组化验证特定细胞类型的空间位置;②与已知组织学特征对比(如肿瘤区域应该多肿瘤细胞);③使用多个工具做交叉验证;④人工标注部分spot做benchmark。
六、速查表¶
# ===== 空间解卷积速查 =====
# Cell2location (Python)
pip install cell2location
# Step 1: 训练参考模型
mod_ref = RegressionModel(adata_ref)
mod_ref.train(max_epochs=250)
# Step 2: 空间解卷积
mod_vis = Cell2location(adata_vis, cell_state_df=inf_aver)
mod_vis.train(max_epochs=30000)
# 结果: adata_vis.obsm["q05_cell_abundance_w_sf"]
# RCTD (R)
library(spacexr)
reference <- Reference(counts, cell_types, nUMI)
puck <- SpatialRNA(coords, counts, nUMI)
myRCTD <- create.RCTD(puck, reference)
myRCTD <- run_RCTD(myRCTD, doublet_mode="full")
# 结果: myRCTD@results$weights
# 参考数据要求:
# 同组织同物种 + 每种细胞类型≥25个 + 注释准确