单细胞肿瘤异质性分析¶
一句话说明¶
肿瘤不是一团均匀的坏细胞,而是由多个遗传背景不同的"亚群"组成的混合体,单细胞测序能看清每个细胞的突变和表达差异,揭示肿瘤内部的异质性格局。
核心知识点¶
1. 肿瘤异质性层次¶
- 瘤间异质性(inter-tumor):不同患者的肿瘤不同(白话:每个病人的肿瘤都独一无二)
- 瘤内异质性(intra-tumor):同一个肿瘤内不同区域/细胞不同(白话:一个肿瘤内部也不统一)
- 时间异质性:治疗前后肿瘤的组成变化
- 白话类比:肿瘤像一个生态系统,里面住着不同"物种"(亚克隆),它们竞争、合作、演化
2. 单细胞分析揭示的异质性维度¶
| 维度 | 方法 | 工具 |
|---|---|---|
| 转录异质性 | scRNA-seq 聚类 | Seurat, Scanpy |
| 基因组异质性 | 单细胞CNV推断 | InferCNV, CopyKAT |
| 克隆结构 | 突变追踪 | Clonealign, Cardelino |
| 细胞状态 | 轨迹分析 | Monocle3, scVelo |
| 微环境互作 | 通讯分析 | CellChat, CellPhoneDB |
3. InferCNV 从表达推断 CNV¶
- 原理:如果某个染色体区域的基因表达整体偏高/偏低,可能是因为拷贝数变了
- 需要正常细胞作为参考(从同一数据中选择免疫细胞或成纤维细胞)
- 可以区分不同 CNV 模式的亚克隆
4. 肿瘤微环境(TME)解析¶
- 免疫细胞:T 细胞(CD8+ 效应/耗竭)、Treg、巨噬细胞(M1/M2)
- 基质细胞:成纤维细胞(CAF)、内皮细胞
- 肿瘤细胞本身的亚群和状态
实战代码¶
# === 单细胞肿瘤异质性分析(Scanpy + InferCNV) ===
import scanpy as sc # 单细胞分析
import numpy as np # 数值计算
# 1. 加载和预处理
adata = sc.read_10x_h5("filtered_feature_bc_matrix.h5") # 10X数据
adata.var_names_make_unique() # 基因名去重
sc.pp.filter_cells(adata, min_genes=200) # 过滤低质量细胞
sc.pp.filter_genes(adata, min_cells=3) # 过滤低表达基因
# 计算线粒体基因比例(肿瘤细胞可能偏高)
adata.var["mt"] = adata.var_names.str.startswith("MT-")
sc.pp.calculate_qc_metrics(adata, qc_vars=["mt"], inplace=True)
adata = adata[adata.obs.pct_counts_mt < 20].copy() # 过滤高线粒体
# 标准处理
sc.pp.normalize_total(adata, target_sum=1e4) # 归一化
sc.pp.log1p(adata) # 对数变换
sc.pp.highly_variable_genes(adata, n_top_genes=3000) # 高变异基因
sc.pp.scale(adata, max_value=10) # 标准化
sc.tl.pca(adata, svd_solver="arpack") # PCA降维
sc.pp.neighbors(adata, n_pcs=30) # 构建KNN图
sc.tl.umap(adata) # UMAP降维
sc.tl.leiden(adata, resolution=0.8) # Leiden聚类
# 2. 区分肿瘤细胞和非肿瘤细胞(用marker基因)
# 免疫细胞 marker
immune_markers = ["PTPRC", "CD3D", "CD8A", "CD4", "CD14", "CD68"]
# 上皮/肿瘤 marker
tumor_markers = ["EPCAM", "KRT18", "KRT19", "MUC1"]
sc.pl.dotplot(adata, immune_markers + tumor_markers,
groupby="leiden") # 点图查看marker表达
# 3. 手动注释细胞类型(根据marker表达)
cell_type_map = {
"0": "Tumor", "1": "Tumor", "2": "T_cell",
"3": "Macrophage", "4": "Tumor", "5": "Fibroblast",
"6": "B_cell", "7": "Endothelial" # 根据实际marker调整
}
adata.obs["cell_type"] = adata.obs["leiden"].map(cell_type_map)
# 4. 分析肿瘤细胞亚群
tumor_cells = adata[adata.obs["cell_type"] == "Tumor"].copy()
sc.tl.leiden(tumor_cells, resolution=0.5, key_added="tumor_subclone")
sc.pl.umap(tumor_cells, color="tumor_subclone",
title="肿瘤细胞亚克隆") # 可视化亚克隆
# === InferCNV 从 scRNA-seq 推断 CNV ===
# 1. 准备输入文件
# annotations.txt: 每个细胞的类型注释(肿瘤/正常)
# gene_order.txt: 基因在染色体上的位置
# 2. 运行 InferCNV(R 脚本)
cat > run_infercnv.R << 'RSCRIPT'
library(infercnv) # 加载InferCNV
# 创建 InferCNV 对象
infercnv_obj <- CreateInfercnvObject(
raw_counts_matrix = "raw_counts.txt", # 原始计数矩阵
annotations_file = "annotations.txt", # 细胞注释
gene_order_file = "gene_order.txt", # 基因位置
ref_group_names = c("T_cell", "Macrophage") # 正常参考细胞
)
# 运行分析
infercnv_obj <- infercnv::run(
infercnv_obj, # InferCNV对象
cutoff = 0.1, # 基因表达下限
out_dir = "infercnv_output/", # 输出目录
cluster_by_groups = TRUE, # 按组聚类
denoise = TRUE, # 降噪
HMM = TRUE, # 用HMM识别CNV状态
num_threads = 8 # 线程数
)
RSCRIPT
Rscript run_infercnv.R # 执行R脚本
面试常问点¶
★ 为什么要用单细胞测序分析肿瘤异质性?¶
参考答案:Bulk 测序看到的是所有细胞的平均信号,如果肿瘤中 30% 的细胞有 A 突变、另外 30% 有 B 突变,bulk 测序只能看到两个低频突变,无法知道它们是否在同一个细胞中。单细胞测序能看到每个细胞的独立状态,可以:(1) 识别不同的亚克隆及其比例;(2) 追踪克隆演化路径;(3) 发现治疗耐药的亚群(可能在治疗前就存在的少数耐药细胞);(4) 解析肿瘤微环境中免疫细胞的状态(如 T 细胞耗竭)。
★ InferCNV 推断的 CNV 准确吗?¶
参考答案:InferCNV 从表达量推断 CNV,是间接方法,不如 WGS 直接检测准确。它的优势是不需要额外的 DNA 测序,可以在细胞水平看 CNV 模式。大尺度的 CNV(染色体臂级别)检测比较可靠,小尺度的不太准确。最好配合 bulk WGS/WES 的 CNV 数据做验证。CopyKAT 是另一个类似的工具,用贝叶斯方法,某些情况下表现更好。
速查卡片¶
| 问题 | 答案 |
|---|---|
| 瘤内异质性 | 同一肿瘤内不同细胞/区域不同 |
| 单细胞CNV推断 | InferCNV, CopyKAT |
| 转录异质性分析 | Seurat, Scanpy |
| 克隆追踪 | 突变+CNV综合判断 |
| 正常参考细胞 | 免疫细胞、成纤维细胞 |
| TME 解析 | CellChat, CellPhoneDB |
| 亚克隆意义 | 耐药机制、转移能力差异 |
| T细胞耗竭标志 | PDCD1, CTLA4, LAG3, HAVCR2 |
| CAF 标志 | FAP, ACTA2, PDGFRA |
| 分析起点 | 先区分肿瘤细胞和非肿瘤细胞 |