# BACKGROUND.R # BACKGROUND CORRECTION backgroundCorrect <- function(RG, method="auto", offset=0, printer=RG$printer, normexp.method="saddle", verbose=TRUE) { # Apply background correction to microarray data # Gordon Smyth # 12 April 2003. Last modified 1 August 2024. if(is.null(method)) method <- "auto" # Single-channel background correction if(is(RG,"EListRaw")) { RG$E <- backgroundCorrect.matrix(RG$E,RG$Eb,method=method,offset=offset,normexp.method=normexp.method,verbose=verbose) RG$Eb <- NULL return(RG) } # If RG is an unclassed list with a red channel, then convert to RGList if(!isS4(RG) && is.list(RG) && !is.null(RG$R)) RG <- new("RGList",RG) # Two-color background correction if(is(RG,"RGList")) { RG$R <- backgroundCorrect.matrix(RG$R,RG$Rb,method=method,offset=offset,normexp.method=normexp.method,verbose=verbose) RG$Rb <- NULL RG$G <- backgroundCorrect.matrix(RG$G,RG$Gb,method=method,offset=offset,normexp.method=normexp.method,verbose=verbose) RG$Gb <- NULL return(RG) } # Failing all other classes, coerce RG to a matrix RG <- as.matrix(RG) if(!(method %in% c("none","normexp"))) stop(method,"correction requires background intensities") RG <- backgroundCorrect.matrix(RG,method=method,offset=offset,normexp.method=normexp.method,verbose=verbose) return(RG) } backgroundCorrect.matrix <- function(E, Eb=NULL, method="auto", offset=0, printer=NULL, normexp.method="saddle", verbose=TRUE) { # Apply background correction to microarray data # in the form of foreground and background matrices # Gordon Smyth # 30 August 2010. Last modified 30 August 2010. E <- as.matrix(E) if(method=="auto") method <- ifelse(is.null(Eb),"normexp","subtract") method <- match.arg(method, c("none","subtract","half","minimum","movingmin","edwards","normexp")) if(is.null(Eb)) { if(method %in% c("subtract","half","minimum","movingmin","edwards")) method <- "none" } else { Eb <- as.matrix(Eb) } switch(method, subtract={ E <- E-Eb }, half={ E <- pmax(E-Eb, 0.5) }, minimum={ E <- E-Eb for (slide in 1:ncol(E)) { i <- E[,slide] < 1e-18 if(any(i,na.rm=TRUE)) { m <- min(E[!i,slide],na.rm=TRUE) E[i,slide] <- m/2 } } }, movingmin={ if(is.null(printer)) { E <- E-ma3x3.matrix(Eb,FUN=min,na.rm=TRUE) } else { E <- E-ma3x3.spottedarray(Eb,printer=printer,FUN=min,na.rm=TRUE) } }, edwards={ # Log-linear interpolation for dull spots as in Edwards (2003). # The threshold values (delta) are chosen such that the number of # spots with (0 < R-Rb < delta) is f=10% of the number spots # with (R-Rb <= 0) for each channel and array. # Note slight change from Edwards (2003). one <- matrix(1,nrow(E),1) delta.vec <- function(d, f=0.1) { quantile(d, mean(d<1e-16,na.rm=TRUE)*(1+f), na.rm=TRUE) } sub <- E-Eb delta <- one %*% apply(sub, 2, delta.vec) E <- ifelse(sub < delta, delta*exp(1-(Eb+delta)/E), sub) }, normexp={ if(!is.null(Eb)) E <- E-Eb for (j in 1:ncol(E)) { if(verbose) cat("Array",j) x <- E[,j] out <- normexp.fit(x,method=normexp.method) E[,j] <- normexp.signal(out$par,x) if(verbose) cat(" corrected\n") } } ) if(offset) E <- E+offset E } ma3x3.matrix <- function(x,FUN=mean,na.rm=TRUE,...) # 2-dimensional moving average for 3x3 blocks # Gordon Smyth # 11 April 2004 { # Pad out x with NA so that original values have 8 neighbors d1 <- nrow(x) d2 <- ncol(x) y <- matrix(NA,d1+2,d2+2) y[1+(1:d1),1+(1:d2)] <- x # Index vector for original values i <- 1:length(y) dim(i) <- dim(y) i <- i[1+(1:d1),1+(1:d2)] dim(i) <- NULL # Rows are original obs, columns are neighbors x <- matrix(x,d1*d2,9) ry <- nrow(y) x[,1] <- y[i-ry-1] x[,2] <- y[i-ry] x[,3] <- y[i-ry+1] x[,4] <- y[i-1] x[,6] <- y[i+1] x[,7] <- y[i+ry-1] x[,8] <- y[i+ry] x[,9] <- y[i+ry+1] y <- apply(x,MARGIN=1,FUN=FUN,na.rm=na.rm,...) dim(y) <- c(d1,d2) y } ma3x3.spottedarray <- function(x,printer,FUN=mean,na.rm=TRUE,...) # Gordon Smyth # 11 April 2004 { x <- as.matrix(x) narrays <- ncol(x) gr <- printer$ngrid.r gc <- printer$ngrid.c sr <- printer$nspot.r sc <- printer$nspot.c dim(x) <- c(sc, sr, gc, gr, narrays) x <- aperm(x, perm = c(2, 4, 1, 3, 5)) dim(x) <- c(gr * sr, gc * sc, narrays) for (j in 1:narrays) x[,,j] <- ma3x3.matrix(x[,,j],FUN=FUN,na.rm=TRUE,...) dim(x) <- c(sr, gr, sc, gc, narrays) x <- aperm(x, perm = c(3, 1, 4, 2, 5)) dim(x) <- c(sc*sr*gc*gr, narrays) x }