首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >数据挖掘—DESeq2差异基因分析将部分基因padj设置为NA

数据挖掘—DESeq2差异基因分析将部分基因padj设置为NA

原创
作者头像
sheldor没耳朵
发布于 2026-10-20 14:49:27
发布于 2026-10-20 14:49:27
320
举报
文章被收录于专栏:数据挖掘数据挖掘

数据挖掘—DESeq2差异基因分析将部分基因padj设置为NA

最近在分析一个实验室做的转录组测序数据,直接从上游测序公司定量好的count矩阵开始下游的分析。首先,这个上游数据定量是有问题的,其与参考基因组的比对率只有18%左右。具体是哪个环节出了问题,这里不做考究,直接看看直接差异基因分析,能得到什么样的结果。

第一次分析

代码语言:r
复制
rm(list = ls())
library(dplyr)
library(openxlsx)
library(DESeq2)
#大鼠
exp  <- read.xlsx("../data/Rattus norvegicus/Expression_with_annotation.xlsx")
colnames(exp)

select_name <- c("Name","cg_1:read.count","cg_2:read.count","cg_3:read.count",
                 "cg_Icariin_1:read.count","cg_Icariin_2:read.count","cg_Icariin_3:read.count")


exp <- exp[,select_name]
dim(exp) #22016     7

exp[1:2,]

table(duplicated(exp$Name))


#数据清洗
# ---------- 1. 去除重复基因(保留总表达量最高的记录) ----------
exp <- exp %>%
  mutate(TotalCount = rowSums(across(-Name))) %>%
  arrange(desc(TotalCount)) %>%
  distinct(Name, .keep_all = TRUE) %>%
  select(-TotalCount)
exp <- as.data.frame(exp)
rownames(exp) <- exp$Name
exp <- exp[, -1]
colnames(exp) <- c(
  "Control1", "Control2", "Control3",
  "Icariin1", "Icariin2", "Icariin3"
)
exp <- as.matrix(exp)
storage.mode(exp) <- "integer"
dim(exp)#21812     6
head(exp)
sum(duplicated(rownames(exp)))


#过滤
keep_feature <- rowSums (exp > 1) > 1 
table(keep_feature)
exp_clean <- exp[keep_feature, ]  
dim(exp_clean)#7767    6
colnames(exp_clean)
class(exp_clean)
exp_clean <- as.data.frame(exp_clean)


#分组信息
library(stringr)
k = str_detect(colnames(exp),"Control")
table(k) 
Group = ifelse(k,"Control","Icariin")
Group = factor(Group,levels = c("Control","Icariin"))
Group
# [1] Control Control Control Icariin Icariin Icariin
# Levels: Control Icariin


#差异基因分析
group_list <- Group
exprSet = exp_clean

(colData <- data.frame(row.names=colnames(exprSet), 
                       group_list=group_list) )

exprSet[, 1:ncol(exprSet)] <- lapply(exprSet[, 1:ncol(exprSet)], as.integer)

class(exprSet)
dds <- DESeqDataSetFromMatrix(countData = exprSet,
                              colData = colData,
                              design = ~ group_list)
dds <- DESeq(dds) 
res <- results(dds, 
               contrast=c("group_list",
                          levels(group_list)[2],
                          levels(group_list)[1]))
resOrdered <- res[order(res$padj),]
head(resOrdered)
DEG =as.data.frame(resOrdered)
dim(DEG)#7767    6
deg = na.omit(DEG)


#差异基因分析
logFC_t = 0.585
p_t = 0.05

k1 = (deg$pvalue < p_t)&(deg$log2FoldChange < -logFC_t)
k2 = (deg$pvalue < p_t)&(deg$log2FoldChange > logFC_t)
deg = mutate(deg,change = ifelse(k1,"Down",ifelse(k2,"Up","Not")))
table(deg$change)
# Down  Not   Up 
# 13 2469   15 

做到这就能发现问题了,我的dim(exp_clean)是7767 6,即7767个基因,为什么最后的deg$change只显示13 + 2469 +15 = 2497个基因呢?也就是说,有5,270个基因在DESeq2分析后被排除,约占全部基因的67.9%。而这套差异分析的代码我用了很多年了,一直没有出现过这样的情况。

细究之下发现,

代码语言:r
复制
> dim(DEG)#7767    6
[1] 7767    6
> deg = na.omit(DEG)
> dim(deg)
[1] 2497    6
> # 1. 原始表达矩阵基因数
> nrow(exp_clean)
[1] 7767
> # 2. DESeq2完整结果基因数
> nrow(DEG)
[1] 7767
> # 3. na.omit后剩余基因数
> nrow(na.omit(DEG))
[1] 2497
> # 4. 分别检查各列NA数量
> colSums(is.na(DEG))
      baseMean log2FoldChange          lfcSE           stat         pvalue           padj 
             0              0              0              0              0           5270 
> # 5. 检查P值和校正P值
> table(is.na(DEG$pvalue))

FALSE 
 7767 
> table(is.na(DEG$padj))

FALSE  TRUE 
 2497  5270 

即正常情况下,DEG 应该仍有7,767行,每个基因对应一条统计结果,但是,DESeq2的结果中可能存在NA,特别是 padj 列。DESeq2默认采用独立过滤(Independent filtering)机制。对于平均表达量较低、统计检验效能不足的基因,DESeq2可能将其校正后的P值(padj)设置为NA,但这些基因的原始P值(pvalue)仍可能是有效的。

而我设置的的差异表达基因筛选标准是,使用的是原始P值,而不是padj。就可能导致实际上满足设置的差异筛选标准,却被提前删除了。这就可能造成差异表达基因数量被低估。

代码语言:r
复制
#使用原始P值筛选
logFC_t = 0.585
p_t = 0.05

k1 = (deg$pvalue < p_t) &
     (deg$log2FoldChange < -logFC_t)

k2 = (deg$pvalue < p_t) &
     (deg$log2FoldChange > logFC_t)

如我第二次分析,不再执行deg = na.omit(DEG),而是直接执行deg <- DEG,后续分析步骤不变,就会出现差异基因数量显著增多。

代码语言:r
复制
> deg <- DEG
> dim(deg)
[1] 7767    6

...

logFC_t = 0.585
p_t = 0.05

k1 = (deg$pvalue < p_t)&(deg$log2FoldChange < -logFC_t)
k2 = (deg$pvalue < p_t)&(deg$log2FoldChange > logFC_t)
deg = mutate(deg,change = ifelse(k1,"Down",ifelse(k2,"Up","Not")))
table(deg$change)
# Down  Not   Up 
# 77 7615   75 

当然,原来的分析代码并不能说错的,只是又额外过滤了一遍。之前没有注意到这个问题,这次分析了一个有问题的矩阵,显著放大了这个问题,才被我注意到。这里写篇帖子记录下。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 数据挖掘—DESeq2差异基因分析将部分基因padj设置为NA
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档