跳转至

单细胞轨迹分析Monocle

一句话概述:Monocle3通过拟时序(pseudotime)分析将单细胞按发育或分化的先后顺序排列,揭示细胞状态转变的动态轨迹和分支决策点。

核心知识点速览

概念白话解释
拟时序(Pseudotime)把真实时间替换为"发育进度",给细胞排队
轨迹推断把散落的细胞点连成一条"发育路线图"
分支点轨迹分叉的地方,代表细胞"命运选择"的节点
根节点(Root)轨迹的起点,通常是干细胞或祖细胞
UMAP降维可视化方法,把高维数据画到2D平面
PartitionMonocle3把不相连的细胞群分成独立区域
GraphMonocle3构建的轨迹骨架(主图)
CDSCell Data Set,Monocle3的核心数据结构
差异表达基因沿轨迹变化的基因(pseudotime DEGs)
Seurat转换从Seurat对象转为Monocle3的CDS对象

一、Monocle3安装

# 安装Monocle3(需要从GitHub安装)
if (!requireNamespace("BiocManager", quietly = TRUE))
  install.packages("BiocManager")
BiocManager::install(c("BiocGenerics", "DelayedArray", "DelayedMatrixStats",
                        "limma", "lme4", "S4Vectors", "SingleCellExperiment",
                        "SummarizedExperiment", "batchelor", "HDF5Array",
                        "terra", "ggrastr"))  # 安装依赖

install.packages("devtools")  # 安装devtools
devtools::install_github("cole-trapnell-lab/monocle3")  # 安装monocle3

library(monocle3)  # 加载

二、完整分析流程

2.1 从Seurat对象转换

library(Seurat)
library(SeuratWrappers)  # Seurat转换工具
library(monocle3)

# 假设你已有处理好的Seurat对象
# seurat_obj 已完成归一化、聚类和UMAP

# 方法1:用SeuratWrappers转换
cds <- as.cell_data_set(seurat_obj)  # Seurat → CDS

# 方法2:手动构建CDS
expression_matrix <- GetAssayData(seurat_obj, layer = "counts")  # 获取计数矩阵
cell_metadata <- seurat_obj@meta.data  # 获取细胞元数据
gene_metadata <- data.frame(
  gene_short_name = rownames(expression_matrix),  # 基因名
  row.names = rownames(expression_matrix)
)

# 创建CDS对象
cds <- new_cell_data_set(
  expression_data = expression_matrix,  # 表达矩阵
  cell_metadata = cell_metadata,         # 细胞信息
  gene_metadata = gene_metadata          # 基因信息
)

2.2 预处理和降维

# 步骤1:预处理(归一化和选择高变基因)
cds <- preprocess_cds(
  cds,
  num_dim = 50,              # PCA维度数
  method = "PCA"              # 降维方法
)

# 查看PCA解释方差
plot_pc_variance_explained(cds)  # 画碎石图,确定维度数

# 步骤2:去批次效应(可选)
cds <- align_cds(
  cds,
  alignment_group = "batch"  # 按哪个变量校正批次
)

# 步骤3:UMAP降维
cds <- reduce_dimension(
  cds,
  reduction_method = "UMAP",  # 使用UMAP
  preprocess_method = "PCA"   # 基于PCA结果
)

# 可视化
plot_cells(cds,
           color_cells_by = "cell_type",  # 按细胞类型着色
           label_cell_groups = TRUE,       # 显示标签
           cell_size = 0.5)                # 点大小

2.3 聚类和分区

# 聚类(Leiden算法)
cds <- cluster_cells(
  cds,
  resolution = 1e-3  # 分辨率参数(越小越少cluster)
)

# 查看聚类结果
plot_cells(cds, color_cells_by = "cluster")     # 按cluster着色
plot_cells(cds, color_cells_by = "partition")    # 按partition着色

# Partition很重要!
# 轨迹只在同一个partition内学习
# 如果你想分析的细胞在不同partition,需要设 use_partition=FALSE

2.4 学习轨迹图

# 构建轨迹(核心步骤)
cds <- learn_graph(
  cds,
  use_partition = TRUE,    # 每个partition独立学习轨迹
  close_loop = FALSE       # 是否允许环形轨迹
)

# 可视化轨迹
plot_cells(cds,
           color_cells_by = "cell_type",   # 按细胞类型着色
           label_groups_by_cluster = FALSE, # 不按cluster标注
           label_leaves = FALSE,            # 不标注叶节点
           label_branch_points = TRUE,      # 标注分支点
           graph_label_size = 3)            # 图标签大小

2.5 排序细胞(计算Pseudotime)

# 选择根节点(交互式或程序化)

# 方法1:交互式选择(弹出图形界面)
cds <- order_cells(cds)  # 在弹出的图上点击起始点

# 方法2:程序化选择(推荐,可重复)
# 找到特定细胞类型的节点作为根
get_earliest_principal_node <- function(cds, cell_type = "HSC") {
  cell_ids <- which(colData(cds)$cell_type == cell_type)  # 找到干细胞
  closest_vertex <- cds@principal_graph_aux[["UMAP"]]$pr_graph_cell_proj_closest_vertex
  closest_vertex <- as.matrix(closest_vertex[cell_ids, ])  # 最近的图节点
  root_pr_nodes <- igraph::V(principal_graph(cds)[["UMAP"]])$name  # 所有图节点
  root_pr_nodes[which.min(as.numeric(table(closest_vertex)[root_pr_nodes]))]  # 选择根
}

cds <- order_cells(cds, root_pr_nodes = get_earliest_principal_node(cds, "HSC"))

# 可视化Pseudotime
plot_cells(cds,
           color_cells_by = "pseudotime",   # 按pseudotime着色
           label_cell_groups = FALSE,
           label_leaves = FALSE,
           label_branch_points = FALSE,
           cell_size = 0.5) +
  scale_color_viridis_c()  # 用viridis配色

2.6 沿轨迹的差异基因

# 找沿pseudotime变化的基因
track_genes_result <- graph_test(
  cds,
  neighbor_graph = "principal_graph",  # 使用轨迹图
  cores = 4                             # 并行线程数
)

# 筛选显著基因
sig_genes <- track_genes_result %>%
  filter(q_value < 0.05) %>%           # FDR < 0.05
  arrange(q_value) %>%                  # 按q值排序
  head(100)                             # 取前100个

# 查看特定基因的表达随pseudotime变化
plot_cells(cds,
           genes = c("GATA1", "SPI1", "KLF1"),  # 指定基因
           show_trajectory_graph = TRUE,
           label_cell_groups = FALSE,
           cell_size = 0.5)

# 基因表达沿pseudotime的折线图
plot_genes_in_pseudotime(
  cds[rownames(cds) %in% c("GATA1", "SPI1", "KLF1"), ],  # 选择基因
  color_cells_by = "cell_type",  # 按细胞类型着色
  min_expr = 0.5                  # 最小表达阈值
)

2.7 分支分析

# 在分支点找差异表达基因
# 识别分支决策相关基因

# 获取分支信息
branch_genes <- graph_test(cds, neighbor_graph = "principal_graph")

# 用模块分析(基因分组)
gene_modules <- find_gene_modules(
  cds[rowData(cds)$gene_short_name %in% sig_genes$gene_short_name, ],
  resolution = 1e-2    # 模块分辨率
)

# 可视化基因模块
plot_cells(cds,
           genes = gene_modules,
           label_cell_groups = FALSE,
           show_trajectory_graph = FALSE)

三、将Pseudotime整合回Seurat

# 提取pseudotime值
pseudotime_values <- pseudotime(cds)  # 获取每个细胞的pseudotime

# 添加到Seurat对象
seurat_obj$pseudotime <- pseudotime_values[colnames(seurat_obj)]

# 在Seurat中可视化
FeaturePlot(seurat_obj, features = "pseudotime") +
  scale_color_viridis_c()

# 按pseudotime排序做差异分析
VlnPlot(seurat_obj, features = c("GATA1", "SPI1"),
        group.by = "cell_type", pt.size = 0)

常见报错与解决

报错信息原因解决方案
No root nodes specified没有选择轨迹起点用order_cells()选择根节点
Cells in different partitions要分析的细胞在不同分区设use_partition=FALSE
learn_graph: insufficient cells细胞太少至少需要几百个细胞
as.cell_data_set: missing metadataSeurat对象缺少信息检查meta.data是否完整
pseudotime is Inf某些细胞没有被连接到轨迹检查分区和轨迹图连通性
graph_test: slow基因太多太慢只分析高变基因子集

速查表

# Monocle3标准流程
Seurat → as.cell_data_set() → preprocess_cds()
→ reduce_dimension() → cluster_cells() → learn_graph()
→ order_cells() → plot_cells(color_cells_by="pseudotime")
→ graph_test() → plot_genes_in_pseudotime()

# 核心函数
preprocess_cds()     — 预处理(PCA)
reduce_dimension()   — UMAP降维
cluster_cells()      — 聚类
learn_graph()        — 学习轨迹
order_cells()        — 计算pseudotime
graph_test()         — 轨迹差异基因
plot_cells()         — 可视化

# 参数选择
num_dim: 通常30-50(看碎石图)
resolution: 越小cluster越少
use_partition: TRUE(默认)或FALSE
close_loop: FALSE(大多数情况)

# 根节点选择策略
已知起点: 选干细胞/祖细胞所在节点
未知起点: 选最未分化的cluster
多个起点: 可以运行多次比较

面试高频问题

Q1:什么是Pseudotime?和真实时间有什么关系?

:Pseudotime是一个抽象的"发育进度"度量,表示细胞在发育/分化过程中走了多远。它不等于真实时间——一个pseudotime=5的细胞不一定比pseudotime=3的细胞晚5-3=2天。Pseudotime衡量的是从起点到该细胞的最短路径上,转录组变化的总量。它假设处于不同分化阶段的细胞在同一时间点被捕获,通过表达模式相似性推断先后顺序。

Q2:Monocle3的轨迹推断原理是什么?

:Monocle3先用UMAP降维,然后在降维空间中用逆图嵌入(reversed graph embedding)学习一个主图(principal graph)。这个图是细胞分布的"骨架"——连接的是细胞群的中心而非单个细胞。然后把每个细胞映射到图上最近的点,从用户指定的根节点出发,沿图的最短路径计算每个细胞的pseudotime。分支对应细胞命运的分叉点。

Q3:如何选择轨迹的起点(根节点)?

:需要先验生物学知识。常见策略:①已知干细胞/祖细胞标记(如造血分化中的CD34+HSC)——选这些细胞所在的图节点作为根;②如果不确定,可以看哪些cluster表达已知的"未分化"标记基因;③也可以用RNA velocity作为辅助——velocity指向分化方向,起点应该是velocity的源头。根节点的选择直接影响pseudotime方向和结果解读。

Q4:轨迹分析有什么局限性?

:①需要中间状态存在——如果数据中只有起点和终点细胞没有过渡态,轨迹推断会失败;②时间分辨率有限——pseudotime不等于真实时间;③分支不一定是真实的——噪声和批次效应可能产生虚假分支;④只能分析连续过程——不适合分析不连续的细胞状态变化(如免疫细胞激活);⑤对参数敏感——不同参数可能产生不同轨迹。

Q5:Monocle3和其他轨迹推断工具有什么区别?

:Monocle3的特点是使用主图(principal graph)学习轨迹,能处理复杂的分支和环形结构。与之对比:①Slingshot——基于主曲线(principal curves),更简单但不支持环形轨迹;②RNA velocity(scVelo)——利用剪接/未剪接RNA比例推断方向性,可以和Monocle3互补;③PAGA——基于图抽象化,适合探索性分析和粗粒度轨迹。实际分析中建议多工具验证。