跳转至

742. 单细胞RNA速度分析scVelo

一句话概述:通过比较未剪接RNA(刚转录的)和已剪接RNA(成熟的)的比例,推断每个细胞的发育方向——就像看每个细胞正在"往哪个方向走",从而预测细胞命运。


核心知识点速查表

概念白话解释关键工具
RNA速度(RNA velocity)细胞基因表达的变化速率和方向scVelo, velocyto
未剪接RNA(Unspliced)刚从DNA转录出来,还带着内含子代表"将来的表达"
已剪接RNA(Spliced)去掉内含子的成熟mRNA代表"当前的表达"
潜在时间(Latent time)每个细胞在分化轨迹上的"内部时钟"scVelo动态模型
稳态模型假设大多数基因处于稳态velocyto原始方法
动态模型允许基因在不同细胞中处于不同阶段scVelo EM模型

一、原理(白话版)

1.1 RNA速度的核心思想

基因表达的过程:
DNA → [转录] → pre-mRNA(未剪接) → [剪接] → mRNA(已剪接) → [降解] → 消失

关键洞察:
- 如果一个基因正在"上调":未剪接RNA多,已剪接RNA还没跟上
  → u/s比值高 → 这个基因在"加速"

- 如果一个基因正在"下调":未剪接RNA少,已剪接RNA还没降解完
  → u/s比值低 → 这个基因在"减速"

综合所有基因的速度 → 推断细胞整体的发展方向

1.2 稳态模型 vs 动态模型

特性稳态模型(Velocyto)动态模型(scVelo)
假设大多数细胞处于稳态每个细胞可以在任何阶段
方程ds/dt = β·u - γ·s完整ODE方程组
参数估计线性回归EM算法
适用范围简单分化过程复杂分化/多分支
计算速度

二、分析流程

2.1 准备数据(从BAM文件提取剪接信息)

# ===== 用velocyto提取剪接/未剪接计数 =====
# velocyto从10x Chromium的BAM文件中提取spliced和unspliced RNA

# 安装
pip install velocyto  # 安装velocyto

# 运行(10x Chromium数据)
velocyto run10x \
  /path/to/cellranger/output/ \  # Cell Ranger输出目录
  /path/to/genes.gtf \  # 基因组注释GTF文件
  -m /path/to/repeat_msk.gtf \  # 重复区域mask文件(可选但推荐)
  --samtools-threads 8  # samtools线程数

# 输出:sample.loom文件
# 包含三层矩阵:spliced, unspliced, ambiguous

2.2 scVelo标准分析

# ===== scVelo完整分析流程 =====
import scvelo as scv  # 导入scVelo
import scanpy as sc   # 导入Scanpy
import matplotlib.pyplot as plt  # 导入绑图

# 设置scVelo参数
scv.settings.verbosity = 3  # 显示详细信息
scv.settings.presenter_view = True  # 演示模式(大字体)
scv.set_figure_params("scvelo")  # 使用scVelo默认绘图参数

# ===== 第一步:加载数据 =====
# 方法一:直接加载loom文件
adata = scv.read("sample.loom", cache=True)  # 读取loom文件

# 方法二:将loom与已有的h5ad合并
adata_rna = sc.read_h5ad("processed.h5ad")  # 已处理的scRNA-seq数据
ldata = scv.read("sample.loom")  # velocyto输出的loom文件

# 合并(确保细胞barcode匹配)
adata = scv.utils.merge(adata_rna, ldata)  # 合并spliced/unspliced矩阵到adata

# ===== 第二步:预处理 =====
# 过滤和归一化
scv.pp.filter_and_normalize(
    adata,
    min_shared_counts=20,  # 至少20个细胞共享的基因
    n_top_genes=2000,      # 使用top 2000高变基因
    retain_genes=None      # 不额外保留基因
)

# 计算矩(moments)— 基于邻近细胞平滑表达值
scv.pp.moments(
    adata,
    n_pcs=30,   # 使用30个主成分
    n_neighbors=30  # 每个细胞的30个最近邻
)

# ===== 第三步:估计RNA速度 =====
# 方法一:稳态模型(快速但简单)
scv.tl.velocity(adata, mode="stochastic")  # 随机模型(稳态的改进版)

# 方法二:动态模型(推荐,更准确)
scv.tl.recover_dynamics(adata, n_jobs=8)  # EM算法估计反应速率参数
scv.tl.velocity(adata, mode="dynamical")  # 动态模型

# 构建速度图
scv.tl.velocity_graph(adata)  # 计算细胞间的速度转换概率

# ===== 第四步:可视化 =====
# 在UMAP上显示速度流向
scv.pl.velocity_embedding_stream(
    adata,
    basis="umap",  # 使用UMAP降维
    color="cell_type",  # 按细胞类型着色
    legend_loc="right",
    title="RNA Velocity Stream",
    figsize=(10, 8),
    save="velocity_stream.png",
    dpi=300
)

# 速度箭头图(每个细胞一个箭头)
scv.pl.velocity_embedding(
    adata,
    basis="umap",
    color="cell_type",
    arrow_length=3,    # 箭头长度
    arrow_size=2,      # 箭头大小
    title="RNA Velocity Arrows",
    save="velocity_arrows.png"
)

2.3 潜在时间分析

# ===== 潜在时间(Latent Time)=====
# 只有动态模型才能计算

# 计算潜在时间
scv.tl.latent_time(adata)  # 估计每个细胞的内部时钟

# 可视化潜在时间
scv.pl.scatter(
    adata,
    color="latent_time",  # 按潜在时间着色
    color_map="gnuplot",  # 紫→黄色阶
    size=50,
    title="Latent Time",
    save="latent_time.png"
)

# 查看驱动基因(速度贡献最大的基因)
# 这些基因最能体现分化方向
top_genes = adata.var["fit_likelihood"].sort_values(ascending=False).index[:10]
scv.pl.scatter(
    adata,
    basis=top_genes[:4],  # 显示前4个驱动基因的phase plot
    ncols=2,
    frameon=False,
    save="top_driver_genes.png"
)

# 驱动基因热图
scv.pl.heatmap(
    adata,
    var_names=top_genes,  # 显示top基因
    sortby="latent_time",  # 按潜在时间排序
    col_color="cell_type",  # 列按细胞类型着色
    n_convolve=100,  # 平滑窗口
    save="driver_genes_heatmap.png"
)

2.4 速度置信度评估

# ===== 评估速度结果的可靠性 =====
# 速度置信度
scv.tl.velocity_confidence(adata)  # 计算速度置信度

# 可视化置信度
scv.pl.scatter(
    adata,
    c=["velocity_length", "velocity_confidence"],  # 速度大小和置信度
    cmap="coolwarm",
    perc=[5, 95],
    save="velocity_confidence.png"
)

# PAGA速度(结合PAGA轨迹推断)
scv.tl.paga(
    adata,
    groups="cell_type",  # 按细胞类型分组
    minimum_spanning_tree=False
)

scv.pl.paga(
    adata,
    basis="umap",
    size=50,
    alpha=0.1,
    min_edge_width=2,
    node_size_scale=1.5,
    title="PAGA Velocity",
    save="paga_velocity.png"
)

三、常见报错与解决

报错信息原因解决方案
No spliced/unspliced layersloom文件未正确合并检查adata.layers中是否有spliced和unspliced
Too few cells过滤太严格降低min_shared_counts阈值
Negative velocities everywhere数据质量差或预处理问题检查unspliced比例(应占5-25%)
recover_dynamics: ConvergenceWarningEM未收敛增加max_iter或换用stochastic模式
velocity_graph: memory error细胞数太多下采样到50k细胞以内
Inconsistent velocity direction可能是生物学真实或方法局限对比不同方法(scVelo vs CellRank)

四、面试高频问题

Q1: RNA速度的基本假设是什么?

A: ①转录→剪接→降解的单向过程;②剪接和降解速率在短时间内恒定;③未剪接RNA可以从BAM文件中准确识别;④邻近细胞代表连续的分化状态。

Q2: scVelo的动态模型相比稳态模型好在哪?

A: 稳态模型假设所有细胞都在稳态平衡点附近,只能推断平衡时的速度。动态模型允许每个细胞处于诱导或抑制的不同阶段,能捕捉完整的转录动力学,还能估计"潜在时间"。

Q3: RNA速度有什么局限性?

A: ①依赖未剪接RNA的准确计量(10x数据中unspliced比例本身就低);②不能处理非稳态的剪接速率(如温度变化时);③不能区分"转录增加"和"降解减慢";④在复杂分支中可能给出错误方向。


五、速查表

# ===== scVelo分析速查 =====

# 安装
pip install scvelo

# 提取spliced/unspliced(从Cell Ranger BAM)
velocyto run10x cellranger_output/ genes.gtf

# 标准流程
import scvelo as scv
adata = scv.read("sample.loom")
scv.pp.filter_and_normalize(adata, n_top_genes=2000)
scv.pp.moments(adata, n_pcs=30, n_neighbors=30)

# 动态模型(推荐)
scv.tl.recover_dynamics(adata, n_jobs=8)
scv.tl.velocity(adata, mode="dynamical")
scv.tl.velocity_graph(adata)
scv.tl.latent_time(adata)

# 可视化
scv.pl.velocity_embedding_stream(adata, basis="umap")
scv.pl.scatter(adata, color="latent_time")

# 关键检查
# unspliced比例:5-25%正常
# velocity_confidence > 0.5较可靠