# DECIDETESTS.R
setClass("TestResults",representation("matrix"))
summary.TestResults <- function(object,...)
# Gordon Smyth
# Created 26 Feb 2004. Last modified 6 Jan 2017.
{
Levels <- attr(object,"levels")
if(is.null(Levels)) Levels <- c(-1L,0L,1L)
nlevels <- length(Levels)
tab <- matrix(0L,nlevels,ncol(object))
Labels <- attr(object,"labels")
if(is.null(Labels)) Labels <- as.character(Levels)
dimnames(tab) <- list(Labels,colnames(object))
for (i in 1:nlevels) tab[i,] <- colSums(object==Levels[i],na.rm=TRUE)
class(tab) <- "table"
tab
}
setMethod("show","TestResults",function(object) {
cat("TestResults matrix\n")
printHead(object@.Data)
})
levels.TestResults <- function(x) attr(x,"levels")
labels.TestResults <- function(object,...) attr(object,"labels")
decideTests <- function(object,...) UseMethod("decideTests")
decideTests.default <- function(object,method="separate",adjust.method="BH",p.value=0.05,lfc=0,coefficients=NULL,cor.matrix=NULL,tstat=NULL,df=Inf,genewise.p.value=NULL,...)
# Accept or reject hypothesis tests across genes and contrasts
# from a matrix of p-values
# Gordon Smyth
# 17 Aug 2004. Last modified 13 Dec 2017.
{
method <- match.arg(method,c("separate","global","hierarchical","nestedF"))
if(method=="nestedF") stop("nestedF adjust method requires an MArrayLM object",call.=FALSE)
adjust.method <- match.arg(adjust.method,c("none","bonferroni","holm","BH","fdr","BY"))
if(adjust.method=="fdr") adjust.method <- "BH"
p <- as.matrix(object)
if(any(p>1) || any(p<0)) stop("object doesn't appear to be a matrix of p-values")
switch(method,
separate={
for (i in 1:ncol(p)) p[,i] <- p.adjust(p[,i],method=adjust.method)
},global={
p[] <- p.adjust(p[],method=adjust.method)
},hierarchical={
if(is.null(genewise.p.value)) {
# Apply Simes' method by rows to get genewise p-values
genewise.p.value <- rep_len(1,nrow(p))
ngenes <- nrow(p)
ncontrasts <- ncol(p)
Simes.multiplier <- ncontrasts/(1:ncontrasts)
for (g in 1:ngenes) {
op <- sort(p[g,],na.last=TRUE)
genewise.p.value[g] <- min(op*Simes.multiplier,na.rm=TRUE)
}
}
# Adjust genewise p-values
DEgene <- p.adjust(genewise.p.value,method=adjust.method) <= p.value
# Adjust row-wise p-values
p[!DEgene,] <- 1
gDE <- which(DEgene)
for (g in gDE) p[g,] <- p.adjust(p[g,],method=adjust.method)
# Adjust p-value cutoff for number of DE genes
nDE <- length(gDE)
a <- switch(adjust.method,
none=1,
bonferroni=1/ngenes,
holm=1/(ngenes-nDE+1),
BH=nDE/ngenes,
BY=nDE/ngenes/sum(1/(1:ngenes))
)
p.value <- a*p.value
},nestedF={
stop("nestedF adjust method requires an MArrayLM object",call.=FALSE)
})
isDE <- array(0L,dim(p),dimnames=dimnames(p))
isDE[p <= p.value] <- 1L
if(is.null(coefficients)) coefficients <- tstat
if(is.null(coefficients)) {
attr(isDE,"levels") <- c(0L,1L)
attr(isDE,"labels") <- c("NotSig","Sig")
} else {
attr(isDE,"levels") <- c(-1L,0L,1L)
attr(isDE,"labels") <- c("Down","NotSig","Up")
coefficients <- as.matrix(coefficients)
if( !all(dim(coefficients)==dim(p)) ) stop("dim(object) disagrees with dim(coefficients)")
i <- coefficients<0
isDE[i] <- -isDE[i]
if(lfc>0) isDE[ abs(coefficients)<lfc ] <- 0L
}
new("TestResults",isDE)
}
decideTests.MArrayLM <- function(object,method="separate",adjust.method="BH",p.value=0.05,lfc=0,...)
# Accept or reject hypothesis tests across genes and contrasts
# Gordon Smyth
# 17 Aug 2004. Last modified 13 Dec 2017.
{
if(is.null(object$p.value)) object <- eBayes(object)
method <- match.arg(method,c("separate","global","hierarchical","nestedF"))
adjust.method <- match.arg(adjust.method,c("none","bonferroni","holm","BH","fdr","BY"))
if(adjust.method=="fdr") adjust.method <- "BH"
switch(method,separate={
p <- as.matrix(object$p.value)
for (j in 1:ncol(p)) {
o <- !is.na(p[,j])
p[o,j] <- p.adjust(p[o,j],method=adjust.method)
}
s <- sign(as.matrix(object$coefficients))
results <- new("TestResults",s*(p<p.value))
},global={
p <- as.matrix(object$p.value)
o <- !is.na(p)
p[o] <- p.adjust(p[o],method=adjust.method)
s <- sign(as.matrix(object$coefficients))
results <- new("TestResults",s*(p<p.value))
},hierarchical={
if(anyNA(object$F.p.value)) stop("Can't handle NA p-values yet")
sel <- p.adjust(object$F.p.value,method=adjust.method) < p.value
i <- sum(sel,na.rm=TRUE)
n <- sum(!is.na(sel))
a <- switch(adjust.method,
none=1,
bonferroni=1/n,
holm=1/(n-i+1),
BH=i/n,
BY=i/n/sum(1/(1:n))
)
results <- new("TestResults",array(0,dim(object$t)))
dimnames(results) <- dimnames(object$coefficients)
if(any(sel)) results[sel,] <- .classifyTestsP(object[sel,],p.value=p.value*a,method=adjust.method)
},nestedF={
if(anyNA(object$F.p.value)) stop("nestedF method can't handle NA p-values",call.=FALSE)
sel <- p.adjust(object$F.p.value,method=adjust.method) < p.value
i <- sum(sel,na.rm=TRUE)
n <- sum(!is.na(sel))
a <- switch(adjust.method,
none=1,
bonferroni=1/n,
holm=1/(n-i+1),
BH=i/n,
BY=i/n/sum(1/(1:n))
)
results <- new("TestResults",array(0,dim(object$t)))
dimnames(results) <- dimnames(object$coefficients)
if(any(sel)) results[sel,] <- classifyTestsF(object[sel,],p.value=p.value*a)
})
if(lfc>0) {
if(is.null(object$coefficients))
warning("lfc ignored because coefficients not found")
else
results@.Data <- results@.Data * (abs(object$coefficients)>lfc)
}
attr(results,"levels") <- c(-1L,0L,1L)
attr(results,"labels") <- c("Down","NotSig","Up")
results
}
classifyTestsF <- function(object,cor.matrix=NULL,df=Inf,p.value=0.01,fstat.only=FALSE) {
# Use F-tests to classify vectors of t-test statistics into outcomes
# Gordon Smyth
# 20 Mar 2003. Last revised 12 Apr 2020.
# Method intended for MArrayLM objects but accept unclassed lists as well
if(is.list(object)) {
if(is.null(object$t)) stop("tstat cannot be extracted from object")
if(is.null(cor.matrix) && !is.null(object$cov.coefficients)) {
# Check for and adjust any coefficient variances exactly zero (usually caused by an all zero contrast)
n <- nrow(object$cov.coefficients)
i <- seq(1L,n)+n*seq.int(0L,n-1L)
if(min(object$cov.coefficients[i]) == 0) {
j <- i[object$cov.coefficients[i] == 0]
object$cov.coefficients[j] <- 1
}
cor.matrix <- cov2cor(object$cov.coefficients)
}
if(missing(df) && !is.null(object$df.prior) && !is.null(object$df.residual)) df <- object$df.prior+object$df.residual
tstat <- as.matrix(object$t)
} else {
tstat <- as.matrix(object)
}
ngenes <- nrow(tstat)
ntests <- ncol(tstat)
if(ntests == 1) {
if(fstat.only) {
fstat <- tstat^2
attr(fstat,"df1") <- 1
attr(fstat,"df2") <- df
return(fstat)
} else {
p <- 2 * pt(abs(tstat), df, lower.tail=FALSE)
return(new("TestResults", sign(tstat) * (p < p.value) ))
}
}
# cor.matrix is estimated correlation matrix of the coefficients
# and also the estimated covariance matrix of the t-statistics
if(is.null(cor.matrix)) {
r <- ntests
Q <- diag(r)/sqrt(r)
} else {
E <- eigen(cor.matrix,symmetric=TRUE)
r <- sum(E$values/E$values[1] > 1e-8)
Q <- .matvec( E$vectors[,1:r], 1/sqrt(E$values[1:r]))/sqrt(r)
}
# Return overall moderated F-statistic only
if(fstat.only) {
fstat <- drop( (tstat %*% Q)^2 %*% array(1,c(r,1)) )
attr(fstat,"df1") <- r
attr(fstat,"df2") <- df
return(fstat)
}
# Return TestResults matrix
qF <- qf(p.value, r, df, lower.tail=FALSE)
if(length(qF)==1) qF <- rep(qF,ngenes)
result <- matrix(0,ngenes,ntests,dimnames=dimnames(tstat))
for (i in 1:ngenes) {
x <- tstat[i,]
if(anyNA(x))
result[i,] <- NA
else
if( crossprod(crossprod(Q,x)) > qF[i] ) {
ord <- order(abs(x),decreasing=TRUE)
result[i,ord[1]] <- sign(x[ord[1]])
for (j in 2:ntests) {
bigger <- ord[1:(j-1)]
x[bigger] <- sign(x[bigger]) * abs(x[ord[j]])
if( crossprod(crossprod(Q,x)) > qF[i] )
result[i,ord[j]] <- sign(x[ord[j]])
else
break
}
}
}
new("TestResults",result)
}
#FStat <- function(object,cor.matrix=NULL)
## Compute overall F-tests given a matrix of t-statistics
## Gordon Smyth
## 24 February 2004. Last modified 21 July 2004.
#{
# m <- as.list(match.call())
# m[[1]] <- as.name("classifyTestsF")
# m$fstat.only <- TRUE
# eval(as.call(m))
#}
.classifyTestsP <- function(object,df=Inf,p.value=0.05,method="holm") {
# TestResults by rows for a matrix t-statistics using adjusted p-values
# Gordon Smyth
# 12 July 2003. Last modified 23 March 2004.
# Method intended for MArrayLM objects but accept unclassed lists as well
if(is.list(object)) {
if(is.null(object$t)) stop("tstat cannot be extracted from object")
tstat <- object$t
if(!is.null(object$df.residual)) df <- object$df.residual
if(!is.null(object$df.prior)) df <- df+object$df.prior
} else {
tstat <- object
}
if(is.null(dim(tstat))) dim(tstat) <- c(1,length(tstat))
ngenes <- nrow(tstat)
P <- 2*pt(-abs(tstat),df=df)
result <- tstat
for (i in 1:ngenes) {
P[i,] <- p.adjust(P[i,],method=method)
result[i,] <- sign(tstat[i,])*(P[i,]<p.value)
}
new("TestResults",result)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.