内容

可靠地拟合γ -泊松广义线性模型。

的核心设计目标gmlGamPoi是:

1安装

的发布版本glmGamPoi从BioConductor:

如果(!requireNamespace("BiocManager", quiet = TRUE)) install.packages("BiocManager")::install("glmGamPoi")

有关最新发展,请参阅GitHub回购。

2例子

加载glmGamPoi包

库(glmGamPoi)

为了拟合一个伽玛-泊松GLM,需要:

# overdispersion = 1/size counts <- rnbinom(n = 10, mu = 5, size = 1/0.7) # design = ~ 1表示只截取模型是适合的适合<- glm_gp(counts, design = ~ 1) fit #> glmGamPoiFit对象:#>数据有1行10列。拟合系数为1的模型。#内部适合只是一个列表:as.list(适合)[1:2]#> $Beta #>拦截#>[1,]1.504077 #> #> $过度分散#> [1]0.3792855

glm_gp ()函数返回一个包含拟合结果的列表。最重要的是,它包含了系数β和过度分散的估计。

为单细胞数据集的每个基因拟合重复的γ -泊松GLMs同样容易:

方法加载一个示例数据集TENxPBMCData包中。该数据集有3.3万个基因和4340个细胞。在完整的数据集上拟合Gamma-Poisson模型大约需要1.5分钟。出于演示目的,我将把数据集子集划分为300个基因,但保留4340个细胞:

库(SummarizedExperiment)库(DelayedMatrixStats)
# 33000个基因的完整的数据集和4340个细胞#第一次运行时,它将下载数据pbmcs < - TENxPBMCData:: TENxPBMCData (pbmc4k) # > snapshotDate(): 2022-04-19 # >看? TENxPBMCData和browseVignettes (TENxPBMCData)文档# >从缓存加载#我希望基因,至少一些重要的非零non_empty_rows <——(rowSums2(化验(pbmcs)) > 0) pbmcs_subset < - pbmcs[示例(non_empty_rows, 300)] pbmcs_subset # >类:SingleCellExperiment # >暗:300 4340 #>元数据(0):#> assays(1):计数#> rownames(300): ENSG00000126457 ENSG00000109832…ENSG00000143819 #> ENSG00000188243 #> rowData names(3): ENSEMBL_ID Symbol_TENx Symbol #> colnames: NULL #> colData names(11): Sample Barcode…#> reducedDimNames(0): #> mainExpName: NULL #> altExpNames(0):

我叫glm_gp ()为每个基因拟合一个GLM模型,并强制在内存中进行计算。

fit <- glm_gp(pbmcs_子集,on_disk = FALSE) summary(fit) #> glmGamPoiFit object: #>数据有300行和4340列。拟合系数为1的模型。# >设计公式是:Y ~ 1 # > # >β:# >最小1瞿瞿。值3。最大# >拦截-8.51 -6.57 - -3.91 -2.59 - 0.903 # > # >异常:# >最小1瞿瞿。值3。最大14 # > 86.8 657 1686 5507 # > # > overdispersion: # >最小1瞿瞿。值3。最大# > 0 1.65 e-13 0.288 - 1.84 24687 # > # >萎缩quasi-likelihood overdispersion: # >最小1瞿瞿。值3。最大1 # > 0.707 - 0.991 1.04 - 7.45 # > # > size_factors: # >最小1瞿瞿。值3。最大# # # > > > 0.117 0.738 1.01 1.32 14.5μ:#>最小第一曲。中位第三曲。最大值#> 2.34e-05 0.00142 0.0185 0.0779 35.8

3.基准

我将我的方法(内存中和磁盘上)与DESeq2而且刨边机.这两种方法都是分析RNA-Seq数据集的经典方法,已经存在了近10年。请注意,这两个工具都可以做很多事情,而不仅仅是拟合Gamma-Poisson模型,因此这个基准测试只能提供性能的一般印象。

#明确意识到数矩阵在内存中,所以它是一个公平的比较pbmcs_subset < - as.matrix(化验(pbmcs_subset)) model_matrix <——矩阵(1,nrow = ncol (pbmcs_subset))板凳::马克(glmGamPoi_in_memory = {glm_gp (pbmcs_subset、设计= model_matrix on_disk = FALSE)}, glmGamPoi_on_disk = {glm_gp (pbmcs_subset、设计= model_matrix on_disk = TRUE)}, DESeq2 = suppressMessages ({dds < - DESeq2:: DESeqDataSetFromMatrix (pbmcs_subset colData = data.frame (name = seq_len (4340)),设计dds < = ~ 1) - DESeq2:: estimateSizeFactors (dds, poscounts) dds < - DESeq2:: estimateDispersions (dds,安静= TRUE) dds < - DESeq2:: nbinomWaldTest (dds, minmu = 1 e-6)}),磨边机= {edgeR_data < -磨边机::DGEList (pbmcs_subset) edgeR_data < -磨边机::calcNormFactors (edgeR_data) edgeR_data < -磨边机::estimateDisp (edgeR_data model_matrix) edgeR_fit < -磨边机::glmFit (edgeR_data、设计= model_matrix)},检查= FALSE, min_iterations = 3) # > #宠物猫:4 × 6 #> expression min median ' itr/sec ' mem_alloc ' gc/sec ' #>       #> 1 glmGamPoi_in_memory 1.44s 2.09s 0.533 NA 4.27 #> 2 glmGamPoi_on_disk 5.18s 5.69s 0.172 NA 1.54 #> 3 DESeq2 18.08s 18.78s 0.0529 NA 0.599 #> 4 edgeR 6.21s 6.53s 0.152 NA 1.26

在这个数据集上,glmGamPoi是不是比快5倍多刨边机速度比DESeq2glmGamPoi使用近似来实现这种性能提升。这种性能来自于一种用于推断每个基因过度分散的优化算法。通过避免重复计算,它针对通常在单个RNA-seq中遇到的具有许多样本和许多小计数的数据集进行了调整。

为了证明该方法不会牺牲准确性,我比较了每种方法估计的参数。均值和β系数是相同的,但过度分散估计glmGamPoi更可靠:

#结果与我的方法适合<- glm_gp(pbmcs_子集,设计= model_matrix, on_disk = FALSE) # DESeq2 dds <- DESeq2::DESeqDataSetFromMatrix(pbmcs_子集,colData = data.frame(name = seq_len(4340)),设计= ~ 1)sizeFactors(dds) <- fit$size_factors dds <- DESeq2:: estimatedispersion (dds, quiet = TRUE) dds <- DESeq2::nbinomWaldTest(dds, minmu = 1e-6) #edgeR edgeR_data <- edgeR::DGEList(pbmcs_子集,lib. 6) #edgeR_data <- edgeR_data::estimateDisp(edgeR_data, model_matrix) edgeR_fit <- edgeR_data::glmFit(edgeR_data, design = model_matrix)

我正在比较这三种方法对系数的基因估计。对角线上的点是相同的。两种方法的Beta系数和基因均值比较吻合,但过度分散的情况存在较大差异。DESeq2有问题估计大部分的过度分散和设置他们1 e-8刨边机仅近似于超分散,这解释了在超分散计算周围的变化glmGamPoi

3.1可伸缩性

该方法随数据集中的行数和列数线性扩展。例如:贴合全pbmc4k数据集和子采样在现代MacBook Pro内存上大约需要1分钟,在磁盘上需要4分钟多一点。拟合的pbmc68k(大小的17倍)在磁盘上花费约73分钟(时间的17倍)。

3.2微分表达式分析

glmGamPoi提供了一个界面,做准似然比测试,以确定差异表达基因。为了演示这个特性,我们将使用来自et al。(2018)MuscData包中。这是8名狼疮患者的单细胞数据集,在干扰素治疗前后进行了10x基于液滴的scRNA-seq。的SingleCellExperiment对象方便地提供患者id (印第安纳州),治疗情况(机枪兵)和细胞类型(细胞):

sce <- muscData::Kang18_8vs8() #> snapshotDate():2022-04-19 # >看? muscData和browseVignettes (muscData)从缓存加载文档# > colData (sce) # > DataFrame 29065行5列# >印第安纳机枪兵集群细胞多胎# > <整数> <因素> <整数> <因素> <因素> # > AAACATACAATGCC-1 107 ctrl CD4 T细胞双重# > AAACATACATTTCC-1 1016 ctrl 9 CD14 +单核细胞单线态# > AAACATACCAGAAA-1 1256 ctrl 9 CD14 +单核细胞单线态# > AAACATACCAGCTA-1 1256 ctrl 9 CD14 +单核细胞双重# > AAACATACCATGCA-1 1488 ctrl CD4 T细胞单线#> ... ... ... ... ... ...#> TTTGCATGGGACGA-1 1488 stim 6 CD4 T细胞单链#> TTTGCATGGTGAGG-1 1488 stim 6 CD4 T细胞ambs #> tttgcatggttttggg -1 1244 stim 6 CD4 T细胞ambs #> TTTGCATGTCTTAC-1 1016 stim 5 CD4 T细胞单链#> TTTGCATGGGACGA-1

为了演示,我将研究基因和细胞的一个子集:

set.seed(1) #取高表达基因和合适的细胞:sce_子集<- sce[rowsum (counts(sce)) > 100, sample(which(sce$multiplets == "singlet" & !is.na(sce$cell) & sce$cell %in% c("CD4 T细胞","B细胞","NK细胞")),1000)]#将计数转换为密集矩阵计数(sce_子集)<- as.matrix(counts(sce_子集))#删除空级别,因为glm_gp()将投诉否则sce_子集$cell <- droplevels(sce_子集$cell)

我们将确定CD4阳性t细胞中的哪些基因在治疗中变化最大。我们将拟合一个包括相互作用项的完整模型敌人:细胞.相互作用术语将帮助我们识别对治疗的特定细胞类型的反应:

fit <- glm_gp(sce_子集,design = ~ cell + stim + stim:cell - 1, reference_level = "NK cells") summary(fit) #> glmGamPoiFit object: #>数据有9727行,1000列。拟合6个系数的模型。设计公式为:Y~cell + stim + stim:cell -1 #> #> Beta: #> Min 1st Qu. Median 3rd Qu. Max #> cellNK cells -1e+08 -1.00e+08 -3.74 -2.65 4.44 #> cellB cells -1e+08 -1.00e+08 -3.88 -2.94 4.47 #> cellCD4 T cells -1e+08 -5.13e+00 -4.20 -3.05 4.50 #>…# > # >异常:# >最小1瞿瞿。值3。最大61.9 # > 0 114 251 5706 # > # > overdispersion: # >最小1瞿瞿。值3。最大# > 0 0 0.528 4.01 2762 # > # >萎缩quasi-likelihood overdispersion: # >最小1瞿瞿。值3。最大# 1.07 > 0.188 - 0.994 363 # > # > size_factors: # >最小1瞿瞿。值3。最大# # # > > > 0.489 0.815 1.01 1.2 5.97μ:# >最小1瞿瞿。值3。最大# > 0 0.00364 0.016 0.0498 537

为了了解我们的模型的系数是如何被称为的,我们看看colnames(适合β美元)

colnames(fit$Beta) #>[1]“cellNK细胞”“cellB细胞”#>[3]“cellCD4 T细胞”“stimstim”#>[5]“cellB细胞:stimstim”“cellCD4 T细胞:stimstim”

在我们的例子中,我们想要找到T细胞中特异变化的基因。发现细胞类型对治疗的特定反应是单细胞数据相对于批量数据的一大优势。为了得到不确定性的正确估计(来自同一供体的细胞是独立复制),我们为每个样本创建一个伪块:

对比参数指定我们想要比较的内容#我们测试受刺激t细胞和对照t细胞的表达差异# # colData中没有样本标签,因此我们从colData中的' stim '和' ind '列动态创建它# (fit$data)。de_res <- test_de(fit, contrast = ' stimstim ' + ' cellCD4 T cells:stimstim ', pseudobulk_by = paste0(stim, "-", ind)) #大的' lfc '值来自几乎所有计数都为0的组#将它们设置为Inf使图看起来更好de_res$lfc <- ifelse(abs(de_res$lfc) > 20, sign(de_res$lfc) * Inf, de_res$lfc) #大多数不同的基因头(de_res[order(de_res$pval),]) #> name pval adj_pval f_statistic df1 df2 lfc #> 189 IFI6 1.216668e-07 0.0008317393 37.21844 1 53.44554 6.118008 #> 6691 PSME2 1.710166e-07 0.0008317393 36.09857 1 53.44554 3.519394 #> 5181 IFIT3 1.572027e-06 0.0050970346 29.15329 1 53.44554 7.872549 #> 9689 MX1 5.336265e-06 0.0129764629 25.57692 1 53.44554 5.037912 #> 5356 IRF7 1.087097e-05 0.0216575952 23.00332 1 53.44554 4.670868 #> 2321 IGJ 1.335927e-05 0.0216575952 -12.445271

该测试是成功的,我们发现了干扰素刺激的T细胞中差异表达的有趣基因:IFI6IFIT3,IRF7字面意思是干扰素诱导/调节蛋白

为了更全面地了解结果,我们可以制作一个火山图,比较log2倍变化(LFC)和对数化p值。

库(ggplot2) ggplot(de_res, aes(x = lfc, y = -log10(pval))) + geom_point(size = 0.6, aes(color = adj_pval < 0.1)) + ggtitle(“火山图”,“T细胞中通过干扰素- β治疗变化最大的基因”)

单细胞数据分析的另一个重要任务是识别细胞簇的标记基因。为此,我们还可以使用伽马-泊松拟合。

假设我们想要找到T细胞和B细胞之间不同的基因。我们可以直接比较对应的系数,找到对照条件下不同的基因:

marker_genes <- test_de(fit, ' cellCD4 T细胞' - ' cellB细胞',sort_by = pval) head(marker_genes) #> name pval adj_pval f_statistic df1 #> 2873 CD74 9.414545e-198 9.157528e-194 1411.8278 1 #> 3150 hla - drb1_ensg00000204287 7.389641e-180 3.593952e-176 1228.0745 1 #> 3152 hla - drb1_ensg00000105369 2.307338e-74 5.610870e-71 390.5803 1 #> 3166 HLA-DPA1_ENSG00000231389 3.226069e-70 6.275995e-67 364.8244 1 #> 3167 HLA-DPB1_ENSG00000223865 2.259768e -61 329.2877 1 #> df2 lfc #> 28731070.895 -5.052300 #> 3150 1070.895 -7.143245 #> 3152 1070.895 -6.993047 #> 9116 1070.895 -7.282279 #> 3166 1070.895 -5.004210 #> 3167 1070.895 -4.257008

如果我们想要找到在刺激条件下不同的基因,我们只需要在对比中加入额外的系数:

mark_genes2 <- test_de(fit, (' cellCD4 T cells ' + ' cellCD4 T cells:stimstim ') - (' cellB cells ' + ' cellB cells:stimstim '),sort_by = pval) head(marker_genes2) #> name pval adj_pval f_statistic df1 #> 2873 CD74 8.764655e-187 8.525380e- 175 2.579763e-171 1180.6034 1 #> 3150 hla - drb1_ensg00000204287 5.304335e-175 2.579763e- 106 626.9933 1 #> 3166 HLA-DPA1_ENSG00000231389 2.972347e-85 7.228005e-82 460.4820 1 #> 9116 CD79A_ENSG00000105369 1.327524e-58 2.152138e-55 295.0837 1 #> df2 lfc #> 28731070.895 -4.753566e+00 #> 3150 1070.895 -6.635859e+00 #> 3152 1070.895 -5.969909e+00 #> 3166 1070.895 -5.207105e+00 #> 3167 1070.895 -5.086061e+00 #> 9116 1070.895 -1.442695e+08

我们发现了许多与人类白细胞抗原(HLA)系统相关的基因,这些基因对抗原提呈细胞如b细胞很重要,但不被T辅助细胞表达。下图显示了表达差异。

注意:申请test_de ()对于没有伪块的单细胞数据,会给出过于乐观的p值。这是因为来自同一样本的细胞不是独立的复制!只要人们意识到解释结果的困难,使用这种方法来识别标记基因仍然是好的。

#创建一个data.frame表达式值,基因名称和细胞类型tmp < - data.frame(基因=代表(marker_genes名称[1:6],美元乘以= ncol (sce_subset)),表达= c(计数(sce_subset) [marker_genes $名称[1:6]]),celltype =代表(sce_subset细胞,美元= 6))ggplot (tmp, aes (x = celltype, y =表达式)+ geom_jitter(身高= 0.1)+ stat_summary(几何学=“横梁”,有趣=“的意思是”,颜色=“红色”)+ facet_wrap(~基因,尺度=“free_y”)+ ggtitle(“B与T细胞的标记基因”)

4会话信息

sessionInfo() #> R version 4.2.0 RC (2022-04-19 r82224) #>平台:x86_64-pc-linux-gnu (64-bit) #>运行在:Ubuntu 20.04.4 LTS #> #>矩阵产品:默认#> BLAS: /home/biocbuild/bbs-3.15-bioc/R/lib/libRblas。所以#> LAPACK: /home/biocbuild/bbs-3.15-bioc/R/lib/libRlapack。so #> #> locale: #> [1] LC_CTYPE=en_US。UTF-8 LC_NUMERIC= c# > [3] LC_TIME=en_GB LC_COLLATE= c# > [5] LC_MONETARY=en_US。utf - 8 LC_MESSAGES = en_US。UTF-8 #> [7] LC_PAPER=en_US。UTF-8 LC_NAME= c# > [9] LC_ADDRESS=C LC_TELEPHONE= c# > [11] LC_MEASUREMENT=en_US。UTF-8 LC_IDENTIFICATION= c# > #>附加基础包:#> [1]stats4 stats graphics grDevices utils datasets methods #>[8]基础#> #>其他附加包:# > [1] ggplot2_3.3.5 muscData_1.9.0 # > [3] ExperimentHub_2.4.0 AnnotationHub_3.4.0 # > [5] BiocFileCache_2.4.0 dbplyr_2.1.1 # > [7] TENxPBMCData_1.13.0 HDF5Array_1.24.0 # > [9] rhdf5_2.40.0 SingleCellExperiment_1.18.0 # > [11] DelayedMatrixStats_1.18.0 DelayedArray_0.22.0 # > [13] Matrix_1.4-1 SummarizedExperiment_1.26.0 # > [15] Biobase_2.56.0 GenomicRanges_1.48.0 # > [17] GenomeInfoDb_1.32.0 IRanges_2.30.0 # > [19] S4Vectors_0.34.0 BiocGenerics_0.42.0 # > [21] MatrixGenerics_1.8.0 matrixStats_0.62.0 # >[23] glmGamPoi_1.8.0 BiocStyle_2.24.0 #> #> loaded via a namespace (and not attached): #> [1] colorspace_2.0-3 ellipsis_0.3.2 #> [3] XVector_0.36.0 farver_2.1.0 #> [5] bit64_4.0.5 interactiveDisplayBase_1.34.0 #> [7] AnnotationDbi_1.58.0 fansi_1.0.3 #> [9] splines_4.2.0 sparseMatrixStats_1.8.0 #> [11] cachem_1.0.6 geneplotter_1.74.0 #> [13] knitr_1.38 jsonlite_1.8.0 #> [15] annotate_1.74.0 png_0.1-7 #> [17] shiny_1.7.1 BiocManager_1.30.17 #> [19] compiler_4.2.0 httr_1.4.2 #> [21] assertthat_0.2.1 fastmap_1.1.0 #> [23] bench_1.1.2 limma_3.52.0 #> [25] cli_3.3.0 later_1.3.0 #> [27] htmltools_0.5.2 tools_4.2.0 #> [29] gtable_0.3.0 glue_1.6.2 #> [31] GenomeInfoDbData_1.2.8 dplyr_1.0.8 #> [33] rappdirs_0.3.3 Rcpp_1.0.8.3 #> [35] jquerylib_0.1.4 vctrs_0.4.1 #> [37] Biostrings_2.64.0 rhdf5filters_1.8.0 #> [39] xfun_0.30 stringr_1.4.0 #> [41] beachmat_2.12.0 mime_0.12 #> [43] lifecycle_1.0.1 XML_3.99-0.9 #> [45] edgeR_3.38.0 zlibbioc_1.42.0 #> [47] scales_1.2.0 promises_1.2.0.1 #> [49] parallel_4.2.0 RColorBrewer_1.1-3 #> [51] yaml_2.3.5 curl_4.3.2 #> [53] memoise_2.0.1 sass_0.4.1 #> [55] stringi_1.7.6 RSQLite_2.2.12 #> [57] highr_0.9 BiocVersion_3.15.2 #> [59] genefilter_1.78.0 filelock_1.0.2 #> [61] BiocParallel_1.30.0 rlang_1.0.2 #> [63] pkgconfig_2.0.3 bitops_1.0-7 #> [65] evaluate_0.15 lattice_0.20-45 #> [67] purrr_0.3.4 Rhdf5lib_1.18.0 #> [69] labeling_0.4.2 bit_4.0.4 #> [71] tidyselect_1.1.2 magrittr_2.0.3 #> [73] bookdown_0.26 DESeq2_1.36.0 #> [75] R6_2.5.1 magick_2.7.3 #> [77] generics_0.1.2 DBI_1.1.2 #> [79] pillar_1.7.0 withr_2.5.0 #> [81] survival_3.3-1 KEGGREST_1.36.0 #> [83] RCurl_1.98-1.6 tibble_3.1.6 #> [85] crayon_1.5.1 utf8_1.2.2 #> [87] rmarkdown_2.14 locfit_1.5-9.5 #> [89] grid_4.2.0 blob_1.2.3 #> [91] digest_0.6.29 xtable_1.8-4 #> [93] httpuv_1.6.5 munsell_0.5.0 #> [95] bslib_0.3.1