750. 单细胞表面蛋白CITE-seq进阶¶
一句话概述:CITE-seq同时测量每个细胞的mRNA和表面蛋白,进阶分析包括多模态整合、加权最近邻(WNN)分析、蛋白特异性聚类——就像同时看一个人的"身份证"(基因表达)和"工作服"(表面蛋白)来更精确地判断他的身份。
核心知识点速查表¶
| 概念 | 白话解释 | 关键工具 |
|---|---|---|
| CITE-seq | 用抗体标记测表面蛋白+RNA | 10x, BioLegend |
| ADT | Antibody-Derived Tag,抗体来源的标签 | TotalSeq |
| WNN | 加权最近邻,综合RNA和蛋白信息 | Seurat v4+ |
| CLR | 中心对数比变换,ADT归一化方法 | Seurat |
| DSB | 去除背景和技术噪声的ADT归一化 | dsb R包 |
| 多模态 | 同时分析RNA+蛋白两种数据 | Seurat, muon |
一、原理(白话版)¶
1.1 为什么需要CITE-seq?¶
单纯的scRNA-seq有个问题: - mRNA表达≠蛋白表达(转录后调控、蛋白半衰期) - 很多免疫细胞标记蛋白(CD4、CD8、CD45)在mRNA水平很难区分 - 流式/CyTOF看蛋白但不看RNA
CITE-seq的解决方案:同时测两者 - RNA → 知道基因在干什么 - 蛋白 → 知道细胞"长什么样"(表型)
1.2 进阶分析要点¶
| 分析内容 | 目的 |
|---|---|
| ADT归一化(DSB) | 更准确的蛋白表达定量 |
| WNN分析 | 综合RNA和蛋白做更好的聚类 |
| RNA-蛋白一致性 | 哪些基因mRNA和蛋白相关 |
| 蛋白特异性标记 | 找到只在蛋白水平区分的细胞亚群 |
二、数据处理与归一化¶
2.1 Seurat处理CITE-seq¶
# ===== Seurat处理CITE-seq数据 =====
library(Seurat)
# 读取10x数据(包含RNA和ADT两个矩阵)
data <- Read10X("filtered_feature_bc_matrix/")
# data是一个列表:
# data$`Gene Expression` → RNA矩阵
# data$`Antibody Capture` → ADT矩阵
# 创建Seurat对象(先用RNA)
seurat_obj <- CreateSeuratObject(
counts = data$`Gene Expression`, # RNA counts
project = "CITE-seq",
min.cells = 3, # 基因至少在3个细胞中表达
min.features = 200 # 细胞至少表达200个基因
)
# 添加ADT数据作为新的Assay
seurat_obj[["ADT"]] <- CreateAssayObject(
counts = data$`Antibody Capture`[, colnames(seurat_obj)] # 匹配同样的细胞
)
# 查看ADT蛋白列表
rownames(seurat_obj[["ADT"]])
# CD3, CD4, CD8, CD19, CD56, CD14, CD45RA, CD45RO, ...
2.2 ADT归一化(DSB方法 vs CLR)¶
# ===== 方法一:CLR归一化(Seurat默认)=====
seurat_obj <- NormalizeData(
seurat_obj,
assay = "ADT", # 对ADT做归一化
normalization.method = "CLR", # 中心对数比变换
margin = 2 # 按细胞归一化(margin=2)
)
# ===== 方法二:DSB归一化(推荐,更准确)=====
# DSB可以利用空液滴(empty droplets)作为背景噪声估计
library(dsb)
# 需要:正常细胞的ADT counts + 空液滴的ADT counts
# 空液滴从Cell Ranger的raw_feature_bc_matrix中获取(未过滤的)
raw_data <- Read10X("raw_feature_bc_matrix/")
raw_adt <- raw_data$`Antibody Capture`
# 区分细胞和空液滴
# 简单方法:用RNA的UMI总数区分
rna_umi <- colSums(raw_data$`Gene Expression`)
cell_barcodes <- colnames(seurat_obj) # 已过滤的细胞barcode
empty_barcodes <- setdiff(names(rna_umi[rna_umi < 100]), # UMI<100的是空液滴
cell_barcodes)
# 运行DSB归一化
cell_adt <- as.matrix(data$`Antibody Capture`[, cell_barcodes])
empty_adt <- as.matrix(raw_adt[, empty_barcodes[1:min(10000, length(empty_barcodes))]])
dsb_norm <- DSBNormalizeProtein(
cell_protein_matrix = cell_adt, # 细胞的ADT counts
empty_drop_matrix = empty_adt, # 空液滴的ADT counts
denoise.counts = TRUE, # 去噪
use.isotype.control = TRUE, # 使用同型对照
isotype.control.name.vec = c("IgG1", "IgG2a", "IgG2b") # 同型对照抗体名
)
# 将DSB结果替换到Seurat对象
seurat_obj[["ADT"]] <- CreateAssayObject(data = dsb_norm)
2.3 WNN分析(加权最近邻)¶
# ===== WNN:整合RNA和蛋白信息的聚类 =====
# RNA标准流程
DefaultAssay(seurat_obj) <- "RNA"
seurat_obj <- NormalizeData(seurat_obj)
seurat_obj <- FindVariableFeatures(seurat_obj)
seurat_obj <- ScaleData(seurat_obj)
seurat_obj <- RunPCA(seurat_obj, npcs = 30)
# ADT降维
DefaultAssay(seurat_obj) <- "ADT"
VariableFeatures(seurat_obj) <- rownames(seurat_obj[["ADT"]])
seurat_obj <- ScaleData(seurat_obj)
seurat_obj <- RunPCA(seurat_obj, reduction.name = "apca",
reduction.key = "apca_") # ADT的PCA
# ===== WNN核心步骤 =====
seurat_obj <- FindMultiModalNeighbors(
seurat_obj,
reduction.list = list("pca", "apca"), # 两种降维结果
dims.list = list(1:30, 1:15), # 各自使用的维度数
modality.weight.name = "RNA.weight" # 权重名称
)
# WNN聚类
seurat_obj <- FindClusters(
seurat_obj,
graph.name = "wsnn", # 使用WNN图
algorithm = 3, # SLM算法
resolution = 0.5
)
# WNN UMAP
seurat_obj <- RunUMAP(
seurat_obj,
nn.name = "weighted.nn", # 使用WNN
reduction.name = "wnn.umap", # 输出名称
reduction.key = "wnnUMAP_"
)
# ===== 对比三种聚类 =====
p1 <- DimPlot(seurat_obj, reduction="wnn.umap", group.by="wsnn_res.0.5",
label=TRUE) + ggtitle("WNN Clusters")
p2 <- DimPlot(seurat_obj, reduction="wnn.umap", group.by="wsnn_res.0.5",
split.by=NULL) + ggtitle("RNA weight per cell")
# 查看每个细胞RNA和ADT权重
VlnPlot(seurat_obj, features="RNA.weight", group.by="wsnn_res.0.5") +
ggtitle("RNA Weight by Cluster")
# RNA.weight接近1 → 该聚类主要由RNA信息驱动
# RNA.weight接近0 → 该聚类主要由蛋白信息驱动
# 可视化ADT蛋白表达
DefaultAssay(seurat_obj) <- "ADT"
FeaturePlot(seurat_obj,
features = c("CD3", "CD4", "CD8", "CD19", "CD14", "CD56"),
reduction = "wnn.umap", ncol = 3)
ggsave("adt_markers_wnn.png", width=15, height=10, dpi=300)
三、RNA-蛋白一致性分析¶
# ===== 分析mRNA和蛋白表达的一致性 =====
library(ggplot2)
# 提取基因名对应关系(ADT名 vs RNA基因名)
# 通常ADT名如"CD3"对应RNA基因"CD3E"或"CD3D"
gene_protein_map <- data.frame(
ADT = c("CD3", "CD4", "CD8a", "CD14", "CD19", "CD56"),
Gene = c("CD3E", "CD4", "CD8A", "CD14", "CD19", "NCAM1")
)
# 提取表达值
rna_expr <- GetAssayData(seurat_obj, assay="RNA", layer="data")
adt_expr <- GetAssayData(seurat_obj, assay="ADT", layer="data")
# 计算相关性
correlations <- sapply(1:nrow(gene_protein_map), function(i) {
gene <- gene_protein_map$Gene[i]
adt <- gene_protein_map$ADT[i]
if (gene %in% rownames(rna_expr) & adt %in% rownames(adt_expr)) {
cor(rna_expr[gene, ], adt_expr[adt, ], method="spearman")
} else {
NA
}
})
gene_protein_map$Correlation <- correlations
print(gene_protein_map)
# ADT Gene Correlation
# CD3 CD3E 0.72 ← 高相关:mRNA和蛋白一致
# CD4 CD4 0.58 ← 中等:有转录后调控
# CD14 CD14 0.81 ← 高相关
四、常见报错与解决¶
| 报错信息 | 原因 | 解决方案 |
|---|---|---|
ADT: all zeros | ADT数据未正确读取 | 检查feature_ref.csv中的类型 |
DSB: no empty drops | 空液滴数据缺失 | 使用raw_feature_bc_matrix |
WNN: dimension mismatch | RNA和ADT的细胞数不一致 | 确保两个assay有相同的细胞 |
Negative DSB values | DSB正常输出(可以有负值) | 负值=低于背景水平,正常 |
ADT normalization选择 | CLR vs DSB不确定 | 有空液滴数据用DSB,没有用CLR |
五、面试高频问题¶
Q1: WNN分析的优势是什么?¶
A: WNN为每个细胞自动学习RNA和蛋白的最优权重。有些细胞类型RNA信息更有用(如基因调控状态),有些蛋白信息更有用(如T细胞亚群的CD标记)。WNN不是简单地把两个模态合并,而是智能加权。
Q2: CLR和DSB归一化有什么区别?¶
A: CLR是成分数据变换,简单直接,不需要空液滴。DSB利用空液滴估计技术背景噪声并去除,同时用同型对照抗体去除非特异性结合,更准确但需要额外数据。
Q3: CITE-seq数据有什么局限性?¶
A: ①抗体panel有限(通常100-300个蛋白,远少于基因组);②抗体质量影响结果(非特异结合、批次差异);③成本高;④不是所有蛋白都有好的抗体。
六、速查表¶
# ===== CITE-seq分析速查 =====
# 创建对象
data <- Read10X("filtered_feature_bc_matrix/")
obj <- CreateSeuratObject(counts=data$`Gene Expression`)
obj[["ADT"]] <- CreateAssayObject(counts=data$`Antibody Capture`)
# ADT归一化
# CLR: NormalizeData(obj, assay="ADT", method="CLR")
# DSB: DSBNormalizeProtein(cell_adt, empty_adt)
# WNN分析
obj <- FindMultiModalNeighbors(obj,
reduction.list=list("pca","apca"),
dims.list=list(1:30, 1:15))
obj <- FindClusters(obj, graph.name="wsnn")
obj <- RunUMAP(obj, nn.name="weighted.nn")
# 关键蛋白标记:
# T细胞: CD3+ (CD4+ helper, CD8+ cytotoxic)
# B细胞: CD19+, CD20+
# NK: CD56+, CD16+
# 单核: CD14+
# DC: CD11c+, HLA-DR+