美文网首页
DESeq 与 sva 矫正批次效应的原理

DESeq 与 sva 矫正批次效应的原理

作者: 小潤澤 | 来源:发表于2021-11-26 22:58 被阅读0次

代码

我们先上代码:

library(zebrafishRNASeq)
library(sva)
library(RUVSeq)

data(zfGenes)
filter = apply(zfGenes, 1, function(x) length(x[x>5])>=2)
filtered = zfGenes[filter,]
genes = rownames(filtered)[grep("^ENS", rownames(filtered))]
controls = grepl("^ERCC", rownames(filtered))
spikes =  rownames(filtered)[grep("^ERCC", rownames(filtered))]
group = as.factor(rep(c("Ctl", "Trt"), each=3))
set = newSeqExpressionSet(as.matrix(filtered),
                          phenoData = data.frame(group, row.names=colnames(filtered)))
dat0 = counts(set)

# 设计矩阵
## 生物学差异的设计矩阵
mod1 = model.matrix(~group)
## 无差异的设计矩阵
mod0 = cbind(mod1[,1])

# DESeq2
condition <- factor(c(rep("control",3),rep("treat",3)), levels = c("control","treat"))

colData <- data.frame(row.names=colnames(dat0), condition)
dds <- DESeqDataSetFromMatrix(dat0, colData, design= ~ condition)
dds <- DESeq(dds)


dat = counts(dds, normalized=TRUE)
dds_result = data.frame(results(dds, contrast=c("condition","treat","control")))


## Estimate batch with svaseq (unsupervised)
svseq = svaseq(dat0,mod1,mod0,n.sv=2)

## 然后接上DESeq的标准流程
ddssva <- dds
ddssva$SV1 <- svseq$sv[,1]
ddssva$SV2 <- svseq$sv[,2]
design(ddssva) <- ~ SV1 + SV2 + condition

library(magrittr)
ddssva %<>% DESeq

dat_sva = counts(ddssva, normalized=TRUE)
dds_result_sva = data.frame(results(ddssva, contrast=c("condition","treat","control")))
                        

我们注意到,用DESeq矫正批次效应中有一步,利用svaseq()来构造替代变量完成批次效应的矫正

而对于矫正前的log2(FC)



对于矫正后的log2(FC)



最终的效果是log2(FC)有一定的改变

svaseq

我们打开svaseq函数的源代码,目标集中在irwsva.build函数

n.sv = 2
dat = dat0
mod = mod1
mod0 = mod0
  
n <- ncol(dat)
m <- nrow(dat)
  
Id <- diag(n)
# resid为扣除生物学设计所带来的差异的表达矩阵
resid <- dat %*% (Id - mod %*% solve(t(mod) %*% mod) %*% t(mod))  
# 对 resid 进行SVD分解
uu <- eigen(t(resid)%*%resid)
ndf <- n - dim(mod)[2]
  
pprob <- rep(1,m)
one <- rep(1,n)
Id <- diag(n)
df1 <- dim(mod)[2] + n.sv
df0 <- dim(mod0)[2]  + n.sv

## 以下的循环代表多次筛选取均值
B = 5
for(i in 1:B){
    # 计算生物学因素对基因表达差异的影响
    mod.b <- cbind(mod,uu$vectors[,1:n.sv])
    mod0.b <- cbind(mod0,uu$vectors[,1:n.sv])
    ptmp <- f.pvalue(dat,mod.b,mod0.b)
    pprob.b <- (1-edge.lfdr(ptmp))
    
    # 计算unmodel factors对基因表达差异的影响
    mod.gam <- cbind(mod0,uu$vectors[,1:n.sv])
    mod0.gam <- cbind(mod0)
    ptmp <- f.pvalue(dat,mod.gam,mod0.gam)
    pprob.gam <- (1-edge.lfdr(ptmp))
    ## pprob.gam代表unmodel factors对基因表达差异的影响
    ## pprob.b代表生物学因素对基因表达差异的影响
    ## 1-pprob.b代表unmodel factors对基因表达差异的影响
    ## pprob为基因数目维的向量
    pprob <- pprob.gam*(1-pprob.b)
    dats <- dat*pprob
    # 数据中心化
    dats <- dats - rowMeans(dats)
    uu <- eigen(t(dats)%*%dats)
}
  
sv = svd(dats)$v[,1:n.sv, drop=FALSE]

其中:

  1. pprob.gam代表unmodel factors对基因表达差异的影响
  2. pprob.b代表生物学因素对基因表达差异的影响
  3. 1-pprob.b代表unmodel factors对基因表达差异的影响

值得注意的是:

resid <- dat %*% (Id - mod %*% solve(t(mod) %*% mod) %*% t(mod))  

resid为扣除生物学设计所带来的差异的表达矩阵,然后对该矩阵SVD分解:

uu <- eigen(t(resid)%*%resid)

那么uu特征向量为

             sv1          sv2         sv3        sv4       sv5        sv6
Ctl1   0.29441072  0.402479876  0.50127306  0.4083188 0.5472996 -0.1838383
Ctl3  -0.22582801  0.012722701  0.09208784 -0.7791189 0.5472996 -0.1838383
Ctl5  -0.06858271 -0.415202578 -0.59336090  0.3708001 0.5472996 -0.1838383
Trt9  -0.50202545  0.573280615 -0.26598909  0.1234352 0.1838383  0.5472996
Trt11  0.74069432  0.007025239 -0.24253355 -0.2432421 0.1838383  0.5472996
Trt13 -0.23866886 -0.580305854  0.50852263  0.1198069 0.1838383  0.5472996

每一列代表unmodel factors,里面的元素代表不同的unmodel factors对每一个sample的影响
关于SVD分解的生物学意义可以参考:SVD分解在生物学中的意义
只不过这里对sample的影响变为了unmodel factors

然后for循环里面相当于对特征向量 uu 多次操作取平均值

pprob <- pprob.gam*(1-pprob.b)
dats <- dat*pprob

上面语句相当于得到了仅有 unmodel factors 影响下的仅有表达矩阵 dats,因此再次SVD分解,最终取得影响 sample 的特征向量(取前两个sv),而这两个sv就可以看作为 unmodel factors 对sample的影响,把这个加入 DESeq的设计矩阵中去除即可

关于f.pvalue和edge.lfdr函数

其中,函数f.pvalue

dat = dat0

f.pvalue <- function(dat,mod,mod0){
  n <- dim(dat)[2]
  m <- dim(dat)[1]
  df1 <- dim(mod)[2]
  df0 <- dim(mod0)[2]
  p <- rep(0,m)
  Id <- diag(n)
  
  # resid为扣除因素带来的差异的表达矩阵
  resid <- dat %*% (Id - mod %*% solve(t(mod) %*% mod) %*% t(mod))
  # 计算残差矩阵每个元素平方和,作为F分布的参数
  rss1 <- rowSums(resid*resid)
  
  # resid0为未扣除因素的表达矩阵
  resid0 <- dat %*% (Id - mod0 %*% solve(t(mod0) %*% mod0) %*% t(mod0))
  # 计算残差矩阵每个元素平方和,作为F分布的参数
  rss0 <- rowSums(resid0*resid0)
 
  #构造F分布统计量,一个组别是(rss0 - rss1)/(df1-df0),另一个组别是(rss1/(n-df1)
  ## (rss0 - rss1)为参数的分布代表潜在因素所带来的差异的表达值分布
  ### 潜在因素理解为 mod(resid) 设计矩阵以外的因素;而因素理解为mod(resid) 设计矩阵设定的因素
  fstats <- ((rss0 - rss1)/(df1-df0))/(rss1/(n-df1))
  ## 由表达式来看,如果分子分母比值越接近 1,代表因素对该基因的影响越小,反之影响越大
  # 计算F分布p值
  p <-  1-pf(fstats,df1=(df1-df0),df2=(n-df1))
  ## 如果p越大,代表因素对该基因的影响越大
  ## 如果p越小,代表因素对该基因的影响越小
}

其中:

  1. (rss0 - rss1)为参数的分布代表潜在因素所带来的差异的表达值分布
  2. 潜在因素理解为 mod(resid) 设计矩阵以外的因素;而因素理解为mod(resid) 设计矩阵设定的因素
  3. 对于 ((rss0 - rss1)/(df1-df0))/(rss1/(n-df1)) ,代表因素对该基因的影响越小,反之影响越大

对于函数edge.lfdr,它的主要功能是:

adj=1.5
eps=10^-8
lambda=0.8
  
p = ptmp
## 如果p越大,代表因素对该基因的影响越大
## 如果p越小,代表因素对该基因的影响越小
pi0 <- mean(p >= lambda)/(1 - lambda)
pi0 <- min(pi0, 1)
  
n <- length(p)
p <- pmax(p, eps)
p <- pmin(p, 1-eps)
# 将因素对该基因的影响权重累积成个正态分布
# 这个分布的均值是0
x <- qnorm(p)
myd <- density(x, adjust=adj)
mys <- smooth.spline(x=myd$x, y=myd$y)
# 标准化
y <- predict(mys, x)$y
lfdr <- pi0*dnorm(x)/y
  
# 做筛选
lfdr[lfdr > 1] <- 1
lfdr <- lfdr[order(p)]
lfdr <- mono(lfdr)
lfdr <- lfdr[rank(p)]

相关文章

网友评论

      本文标题:DESeq 与 sva 矫正批次效应的原理

      本文链接:https://www.haomeiwen.com/subject/neixxrtx.html