--- title: "GSEAlens:从 limma-voom 和 DESeq2 流程准备输入数据" author: "Shenhui Xu" date: "`r Sys.Date()`" output: BiocStyle::html_document: toc_float: true number_sections: true vignette: > %\VignetteIndexEntry{GSEAlens:准备输入数据} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include=FALSE} knitr::opts_chunk$set(echo = TRUE, warning = FALSE, message = FALSE) ``` # 安装 GSEAlens 可从 Bioconductor 安装。使用以下命令安装稳定版本: ```{r install-package, eval=FALSE} if (!requireNamespace("BiocManager", quietly = TRUE)) install.packages("BiocManager") BiocManager::install("GSEAlens") ``` 开发版本可从 GitHub 安装: ```{r install-github, eval=FALSE} if (!requireNamespace("pak", quietly = TRUE)) install.packages("pak") pak::pkg_install("DDL095/GSEAlens") ``` # 简介 本 vignette 描述如何准备 `r Biocpkg("GSEAlens")` 所需的输入对象。**GSEAlens 本身 不执行差异表达分析(DEG)**;它接收来自 `r Biocpkg("limma")` 的已拟合 `MArrayLM` 对象或来自 `r Biocpkg("DESeq2")` 的 `DESeqDataSet` 对象。以下步骤基于这些包的标准 工作流程,此处提供是为了完整性。 完整的 DEG 工作流程文档请参阅: - `r Biocpkg("limma")` 和 `r Biocpkg("edgeR")` 的 vignette(limma-voom 流程) - `r Biocpkg("DESeq2")` 的 vignette - `r Biocpkg("airway")` 包提供示例数据集 # 示例数据 我们使用 `r Biocpkg("airway")` 数据集(4 vs 4 样本,dex 处理)。 ```{r setup-environment, results='hide'} library(airway) data(airway) expression_data <- airway ``` # limma-voom 流程 GSEAlens 要求**无截距设计**(`~0+group`),使列名直接对应组别名称,从而精确构建 对比。 ```{r limma-voom-data-preparation} library(edgeR) library(limma) group_level <- expression_data$dex design <- model.matrix(~0+group_level) colnames(design) <- levels(group_level) compare_end <- combn(levels(group_level), 2, simplify = FALSE) contrast_strings <- sapply(compare_end, function(x) paste(x[2], x[1], sep = " - ")) contrast_matrix <- makeContrasts(contrasts = contrast_strings, levels = design) genes_df <- data.frame( gene_id = SummarizedExperiment::rowData(expression_data)$gene_id, symbol = SummarizedExperiment::rowData(expression_data)$symbol, gene_biotype = SummarizedExperiment::rowData(expression_data)$gene_biotype ) genes_df$Length <- SummarizedExperiment::rowData(expression_data)$gene_seq_end - SummarizedExperiment::rowData(expression_data)$gene_seq_start + 1 gsea_limma_voom_data <- edgeR::DGEList( counts = SummarizedExperiment::assay(expression_data, "counts"), genes = genes_df, norm.factors = NULL, group = group_level, remove.zeros = TRUE ) # 过滤低表达基因,保留蛋白质编码 RNA,去重复 symbol total_counts <- edgeR::cpm(gsea_limma_voom_data) |> rowSums() dup_symbols <- gsea_limma_voom_data$genes$symbol[duplicated(gsea_limma_voom_data$genes$symbol)] keep <- rep(TRUE, nrow(gsea_limma_voom_data)) for (gene in dup_symbols) { idx <- which(gsea_limma_voom_data$genes$symbol == gene) best_idx <- idx[which.max(total_counts[idx])] remove_idx <- idx[idx != best_idx] keep[remove_idx] <- FALSE } gsea_limma_voom_data <- gsea_limma_voom_data[keep, ] rownames(gsea_limma_voom_data) <- gsea_limma_voom_data$genes$symbol keep_biotype <- gsea_limma_voom_data$genes$gene_biotype == "protein_coding" gsea_limma_voom_data <- gsea_limma_voom_data[keep_biotype, ] gsea_limma_voom_data <- edgeR::normLibSizes(gsea_limma_voom_data, method = "TMM") isexpr <- rowSums(edgeR::cpm(gsea_limma_voom_data) > 1) >= 3 gsea_limma_voom_data <- gsea_limma_voom_data[isexpr, ] ``` 进行 limma-voom 拟合,获取 `fit` 对象。 ```{r limma-voom-processing} VoomOutPut <- voom(gsea_limma_voom_data, design) fit <- lmFit(object = VoomOutPut, design = design) |> contrasts.fit(contrasts = contrast_matrix) |> eBayes() ``` # DESeq2 流程(SummarizedExperiment 输入) ```{r deseq2-se-workflow} library("DESeq2") dds_se <- DESeqDataSet(expression_data, design = ~ cell + dex) # 仅保留蛋白编码基因 gene_biotypes <- SummarizedExperiment::rowData(dds_se)$gene_biotype keep_protein_coding <- gene_biotypes == "protein_coding" dds_se <- dds_se[keep_protein_coding, ] # 去除低表达基因(要求 >=10 reads 且至少出现在 >=3 个样本中) smallestGroupSize <- 3 keep <- rowSums(DESeq2::counts(dds_se) >= 10) >= smallestGroupSize dds_se <- dds_se[keep, ] # 基因符号去重,保留表达量最高的那一行 rownames(dds_se) <- SummarizedExperiment::rowData(dds_se)$gene_name total_counts <- rowSums(SummarizedExperiment::assay(dds_se)) dup_genes <- rownames(dds_se)[duplicated(rownames(dds_se))] keep <- rep(TRUE, nrow(dds_se)) for (gene in dup_genes) { idx <- which(rownames(dds_se) == gene) best_idx <- idx[which.max(total_counts[idx])] remove_idx <- idx[idx != best_idx] keep[remove_idx] <- FALSE } dds_se <- dds_se[keep, ] # 运行 DESeq2 拟合 dds_se <- DESeq(dds_se) ``` # DESeq2 流程(Count Matrix 输入) ```{r deseq2-matrix-workflow} DDS_rawdata <- expression_data # 仅保留蛋白编码基因 gene_biotypes <- SummarizedExperiment::rowData(DDS_rawdata)$gene_biotype keep_protein_coding <- gene_biotypes == "protein_coding" DDS_rawdata <- DDS_rawdata[keep_protein_coding, ] # 去除低表达基因 smallestGroupSize <- 3 keep_epd <- rowSums(SummarizedExperiment::assay(DDS_rawdata, "counts") >= 10) >= smallestGroupSize DDS_rawdata <- DDS_rawdata[keep_epd, ] # 基因符号去重 rownames(DDS_rawdata) <- SummarizedExperiment::rowData(DDS_rawdata)$gene_name total_counts <- rowSums(SummarizedExperiment::assay(DDS_rawdata)) keep_name <- rep(TRUE, nrow(DDS_rawdata)) dup_genes <- rownames(DDS_rawdata)[duplicated(rownames(DDS_rawdata))] for (gene in dup_genes) { idx <- which(rownames(DDS_rawdata) == gene) best_idx <- idx[which.max(total_counts[idx])] remove_idx <- idx[idx != best_idx] keep_name[remove_idx] <- FALSE } DDS_rawdata <- DDS_rawdata[keep_name, ] # 抽取 counts 矩阵和样本元数据 cts <- SummarizedExperiment::assay(DDS_rawdata, "counts") coldata <- as.data.frame(SummarizedExperiment::colData(DDS_rawdata)) coldata <- coldata[, c("cell", "dex")] coldata$cell <- factor(coldata$cell) coldata$dex <- factor(coldata$dex) # 从矩阵构建 DESeqDataSet 并运行 DESeq2 dds <- DESeqDataSetFromMatrix(countData = cts, colData = coldata, design = ~ dex) dds <- DESeq(dds) ``` # 下一步 `fit`、`dds_se` 和 `dds` 准备就绪后,返回主 vignette: ```r vignette("GSEAlens") ``` ```{r sessionInfo} sessionInfo() ```