单细胞空转CNV分析工具:比 inferCNV 快10倍?!兼容单细胞与空转的 CNV 分析与聚类,竟然还支持肿瘤的亚克隆树构建!

生信碱移

快速CNV分析

fastCNV 是scRNA-seq与空间转录组(含Visium HD)的快速 CNV 推断工具,比常规工具 inferCNV 运行速度快 10 倍,平均内存占用减少 94%。不仅如此,fastCNV 通过将 spots/cells 聚合为 meta-spots/meta-cells 以增强信号,输出全基因组 CNV 热图,并进行 CNV 聚类、克隆树推断与染色体臂级别 CNV 事件注释。

DNA拷贝数变异(CNV)在肿瘤发生发展中占据核心地位,其既可能通过抑癌基因缺失或致癌基因扩增驱动病理过程,也会在肿瘤演化中逐步累积,塑造显著的肿瘤内异质性,并影响生长、耐药与预后。

临床上,CNV 通常依赖 WES/WGS 等 DNA 测序手段进行检测。单细胞转录组与空间转录组(ST)在解析组织结构与细胞状态方面优势突出,如果能够从这些转录组数据中推断CNV,就有机会以更低成本、更高空间/细胞分辨率描绘肿瘤克隆结构。尽管如此,现有 CNV 分析工具难以处理大规模数据,包括运行速度慢、内存消耗高等。

小编也是苦运行速度久矣,这不最近冲浪的时候发现了一个刚刚上线的 R 包 fastCNV,能够实现面向 scRNA-seq 与空间转录组的快速精确 CNV 推断。

一开始不得不提一下 fastCNV 的三大特点,具体带大家根据原文的分析结果来看看。

特点一:更高的 CNV 推断准确性。作者选择 117 个 CCLE 癌细胞系,这些细胞系具有全基因组的配对结果。总体来说,fastCNV 与 WES 的相关性整体较高,raw 分数的中位相关性为 0.76(均值0.72),denoised 分数中位数为 0.71(均值0.67)。对比 inferCNV 时,fastCNV 无论在 raw 还是 denoised 层面都显著优于 inferCNV(配对T检验p值分别小于4e-31与8e-24)。

图:fastCNV 与 inferCNV 的性能比较。作者分别对每个细胞系的 scRNA-seq 数据分别运行 fastCNV 与 inferCNV,最终与 WES 推测的 CNV 在同一基因组区域尺度上计算相关性。a图显示 fastCNV 具有高相关性,b图显示 fastCNV 由于inferCNV。

特点二:快速且更低内存占用的 CNV 计算。具体来说,fastCNV 在 117 个细胞系上完成分析需要约 4 分钟,而 inferCNV 则需要约 40 分钟(运行时间快了 10 倍啊)。在此基础上,其平均内存仅为 80 MiB(内存占用约为 inferCNV 的6%),峰值内存约 19 GiB(inferCNV 约 32 GiB)。

图:10次运行下 fastCNV 与 inferCNV 的时间/内存占用比较。

特点三:空间转录组的 CNV 推断与空间亚克隆/演化分析功能。fastCNV 不仅在 scRNA-seq 上做 CNV 打分和聚类,还能把 CNV 簇映射回组织空间位置,用 CNV fraction 等指标区分肿瘤与非肿瘤区域。

图:基于CNV的聚类与打分。

在此基础上能够进一步重建空间层面的克隆结构与克隆树,探究亚克隆出现以及肿瘤演化顺序。

图:CNV得分与亚克隆树构建。

fastCNV 的使用和原理层面且听小编婉婉道来。简单来说,其以 Seurat对象(单样本或多样本列表)作为输入,输出包含 CNV 结果的 Seurat 对象,并可生成类似于 inferCNV 全基因组热图。具体的流程如下:① fastCNV 先用 Louvain 聚类并簇内聚合生成meta cell以增强低读数信号,② 继而基于 Ensembl 将高表达基因按染色体臂滑窗划分区域,③ 对 log2 零中心化表达以二倍体参考校正得到 raw 并截断;④ 再按参考分位去噪生成 denoised 与 CNV fraction,⑤ 最后以层次聚类确定亚克隆并由 CNVTree 基于簇中心构建克隆树并标注臂级增益/缺失。

本文简要介绍 fastCNV 在单细胞与空转数据上的使用,感兴趣的铁子可以进一步阅读原文与 github:

0.R包安装

fastCNV 仅适用于 Seurat5 版本,具体可以使用以下代码安装该包:

复制代码
# R包
remotes::install_github("must-bioinfo/fastCNV")
# 示例数据
remotes::install_github("must-bioinfo/fastCNVdata")

1.单细胞fastCNV分析

① 加载示例数据:

复制代码
library(fastCNV)
library(fastCNVdata)
# 加载 scColon1、scColon2、scColon3、scColon4
# 为结直肠肿瘤单细胞测序数据
# 具体信息见作者原文
utils::data(scColon1)
# 查看数据注释
unique(scColon1[["annot"]])

② 执行fastCNV分析:

复制代码
scColon1 <- fastCNV(seuratObj = scColon1, 
                    sampleName = "scColon1", 
                    referenceVar = "annot", 
                    referenceLabel = c("TNKILC", "Myeloid", "B","Mast", "Plasma"), 
                    printPlot = T)

上述代码在scColon1对象上运行fastCNV()进行CNV推断,其中以annot列中标注为 TNKILC、Myeloid、B、Mast、Plasma 的细胞作为参考二倍体群体(拷贝数正常的细胞群体),并将样本命名为scColon1且输出结果图(printPlot=TRUE)。

③ cnv得分计算。fastCNV 会为 Seurat 对象中的每个观测值计算一个 cnv_fraction (CNV 得分)。可以直接使用 Seurat 的绘图函数对其进行绘制:

复制代码
library(Seurat)
library(ggplot2)

scColon1 <- RunUMAP(scColon1, dims = 1:10)
common_theme <- theme(
  plot.title = element_text(size = 10),
  legend.text = element_text(size = 8),
  legend.title = element_text(size = 8),
  axis.title = element_text(size = 8),
  axis.text = element_text(size = 6)
)

FeaturePlot(scColon1, features = "cnv_fraction", reduction = "umap" ) & common_theme |
  DimPlot(scColon1, reduction = "umap", group.by =  "annot") & common_theme

画个boxplot,可以看到一些细胞亚群的拷贝数变异(CNV)分数比其他簇高得多:

复制代码
ggplot(FetchData(scColon1, vars = c("annot", "cnv_fraction")), 
       aes(annot, cnv_fraction, fill = annot)) +
  geom_boxplot() +
  theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1, color = "black"))

在此基础上,还可以使用 Seurat 的绘图函数来绘制按染色体臂划分的 CNV。对于某些肿瘤,其在特定染色体中会存在显著 CNV 变化的:

复制代码
library(scales)

FeaturePlot(scColon1, features = "20.p_CNV")  +
  scale_color_distiller(palette = "RdBu", direction = -1, limits = c(-1, 1), 
                       rescaler = function(x, to = c(0, 1), from = NULL) {
                         rescale_mid(x, to = to, mid = 0)
                       }) +
  common_theme |
FeaturePlot(scColon1, features = "X.q_CNV") +
  scale_color_distiller(palette = "RdBu", direction = -1, limits = c(-1, 1), 
                       rescaler = function(x, to = c(0, 1), from = NULL) {
                         rescale_mid(x, to = to, mid = 0)
                       }) +
  common_theme

④ CNV 分类。通过使用按染色体臂划分的 CNV 和 CNVclassification函数,可以获得根据染色体臂改变的分类:

复制代码
scColon1 <- CNVClassification(scColon1)

DimPlot(scColon1, group.by = "20.p_CNV_classification") &
  scale_color_manual(values = c(gain = "red", no_alteration = "grey", loss = "blue")) &
  common_theme |
DimPlot(scColon1, group.by = "X.q_CNV_classification") &
  scale_color_manual(values = c(gain = "red", no_alteration = "grey", loss = "blue")) &
  common_theme

⑤ 基于拷贝数变异的聚类簇。fastCNV 还会计算 CNV 聚类,并将其以 "cnv_clusters" 的形式保存在 Seurat 对象的元数据中:

复制代码
DimPlot(scColon1, group.by = "cnv_clusters") + common_theme

通过这个分析,作者发现肿瘤细胞几乎总是属于2/3/4/5 cnv_cluster;而健康细胞往往是 cnv_cluster 1,几乎没有没有拷贝数变异。

⑥ 亚克隆性树构建。如上一小节所述,scColon1 中有 4 个肿瘤亚簇(2/3/4/5),以及 1 个健康亚簇(1)。在此基础上,可以使用 CNVTree() 来构建亚克隆性树:

复制代码
tree_data <- CNVTree(scColon1, values = "calls", cnv_thresh = 0.09, healthyClusters = "1")

2.空转fastCNV分析

① 示例数据加载 (Visium HD 数据,分辨率更高需要更高的内存占用):

复制代码
library(fastCNV)
library(fastCNVdata)
library(Seurat)
# 加载数据
HDBreast <- load_HDBreast()
# 查看注释好的肿瘤/非肿瘤区域
unique(HDBreast[["annots_8um"]])
#>                       annots_8um
#> s_016um_00107_00066-1           
#> s_008um_00269_00526-1    NoTumor
#> s_008um_00260_00253-1      Tumor

值得强调的是,fastCNV 默认使用 16um 测序,如果大家的注释是在 8um 分辨率上的,则需要在对 16um 测序运行 fastCNV 之前先运行下述转换:

复制代码
HDBreast <- annotations8umTo16um(HDBreast, referenceVar = "annots_8um") 
#> [1] "New annotation column (new referenceVar) is named : projected_annots_8um."

上述代码对 16µm 点分配给 8µm 点的注释,生成了projected_annots_8um新的列。在此基础上,可以打印注释看看对不对:

复制代码
SpatialDimPlot(HDBreast, group.by = "projected_annots_8um")

② 运行 fastCNV,参数与单细胞的分析一致。这里将 NoTumor指定为参考:

复制代码
HDBreast <- fastCNV_10XHD(HDBreast, 
                          sampleName = "HDBreast", 
                          referenceVar = "projected_annots_8um", 
                          referenceLabel = "NoTumor", 
                          printPlot = TRUE)

下面的分析就与单细胞类似了,小编不做过多赘述。

③ CNV 分数 (cnv_fraction)。

复制代码
library(patchwork)
SpatialFeaturePlot(HDBreast, "cnv_fraction") | SpatialPlot(HDBreast, group.by = "projected_annots_8um")

两个区域的CNV差异:

复制代码
library(ggplot2)
ggplot(FetchData(HDBreast, vars = c("projected_annots_8um", "cnv_fraction")), 
       aes(projected_annots_8um, cnv_fraction, fill = projected_annots_8um)) +
  geom_boxplot() +
  theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1, color = "black"))

以及按照染色体臂划分的CNV:

复制代码
library(scales)

SpatialFeaturePlot(HDBreast, features = "11.q_CNV")  +
  scale_fill_distiller(palette = "RdBu", direction = -1, limits = c(-0.5, 0.5), 
                       rescaler = function(x, to = c(0, 1), from = NULL) {
                         rescale_mid(x, to = to, mid = 0)
                       }) |
SpatialFeaturePlot(HDBreast, features = "8.q_CNV") +
  scale_fill_distiller(palette = "RdBu", direction = -1, limits = c(-0.5, 0.5), 
                       rescaler = function(x, to = c(0, 1), from = NULL) {
                         rescale_mid(x, to = to, mid = 0)
                       })

④ 基于CNV的聚类簇:

复制代码
HDBreast <- CNVCluster(HDBreast, referenceVar = "projected_annots_8um", tumorLabel = "Tumor")

SpatialDimPlot(HDBreast, group.by = "cnv_clusters") 

比例展示:

复制代码
library(ggplot2)
library(SeuratObject)

HDBreast$cnv_clusters <- as.factor(HDBreast$cnv_clusters)
ggplot(FetchData(HDBreast, vars = c("cnv_clusters", "projected_annots_8um")), aes(projected_annots_8um, fill = cnv_clusters)) +
  geom_bar(position = "fill") +
  theme(axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1, color = "black"))

再次绘制 CNV 热图,在热图中可视化这些聚类:

复制代码
plotCNVResultsHD(HDBreast, referenceVar = "projected_annots_8um", printPlot = TRUE)

⑤ 构建基于CNV的亚克隆树:

复制代码
tree_data <- CNVTree(HDBreast, values ="calls", cnv_thresh = 0.09, healthyClusters = "0")

速度确实快啊,不过得测试测试

准确性似乎也更高?

相关推荐
Frank_refuel3 分钟前
C++STL之set和map的接口使用介绍
数据库·c++·算法
java修仙传3 分钟前
力扣hot100:跳跃游戏||
算法·leetcode·游戏
闻缺陷则喜何志丹4 分钟前
【模拟】P9670 [ICPC 2022 Jinan R] Frozen Scoreboard|普及+
c++·算法·模拟·洛谷
永远都不秃头的程序员(互关)7 分钟前
【K-Means深度探索(十一)】K-Means VS 其他聚类算法:如何选择最合适的工具?
算法·kmeans·聚类
洛生&14 分钟前
Nested Ranges Count
算法
老鼠只爱大米14 分钟前
LeetCode经典算法面试题 #142:环形链表 II(哈希表、快慢指针等多种方法详细解析)
算法·leetcode·链表·快慢指针·floyd算法·环形链表
数智工坊16 分钟前
【操作系统-线程介绍】
linux·算法·ubuntu
肥猪猪爸17 分钟前
NLP中BIO标签浅析
人工智能·深度学习·神经网络·机器学习·自然语言处理·nlp
小龙报19 分钟前
【C语言进阶数据结构与算法】LeetCode27 && LeetCode88顺序表练习:1.移除元素 2.合并两个有序数组
c语言·开发语言·数据结构·c++·算法·链表·visual studio
炽烈小老头19 分钟前
【每天学习一点算法 2026/01/21】倒二进制位
学习·算法