Specifically, a linear model is an equation of the form:
y = beta0 + beta1*x1 + beta2*x2 + beta3 * x3 + .... + epsilon
Lets say you have case where you have gene expression (as assay(vst), as Kevin says), so y is assay(vst). The xs represent the predcitors, so if formula is ~condition + batch, and batch can be "batch1", "batch2" or "batch3", then x1 will be 0 for WT and 1 for treated, x2 will be 1 if batch is "batch2" and x3 will be 1 if batch is "batch3". We often reffer to the x's in the vector form X.
The betas are reffered to as the coefficients. In the sort of gene expression models we are looking at here, where the output is log gene expression, the are equivalent to log fold changes.
episilon represents the random noise in the system - its the bit that isn't accounted for by any of our other predictors.
So we fit this model for each gene, including the batch effects. We then split it into three pieces:
y = (Condition) + (Batch) + episilon
where
Condition = beta0 + beta1*x1
Batch = beta2*x2 + beta3 *x3
and say that if we only want to only get the condition dependent part of the gene expression, is can do:
Condition + epilison = y - (Batch) = y - beta2 * x2 + beta3*x3
We say that this is the "residual" after regressing out the effect of batch.
this is what is happening in this lines:
beta <- fit$coefficients[,-(1:ncol(design)),drop=FALSE]
coefficients is a matrix that contains all the betas (beta0, beta1, beta2, beta3) for all the genes. This gets only those columns associated with batch.
then in this line:
as.matrix(x) - beta %*% t(X.batch)
We multiple the betas by the xs (%*% is matrix multiplication in R, so we multiple the 20,000 x 2 beta matrix by the 2 x nt(X.batch)` matrix to get a 20,000 x n matrix batch effects for each of the 20,000 genes in each of the n samples, and then subtract them from the expressions to leave only the Condition effects.
Related: https://support.bioconductor.org/p/116821/#116828
Have you read the help page
help("removeBatchEffects")?As the author of limma and of the function you're looking at, I don't answer questions about internal code. I only answer questions about the user interface, the documentation and whether the function does what it claims to do.
Why would you not answer questions about open source code?
Life is too short Joe, so priority has to be given to user questions about ... the user interface.
I understand you cant fight all the fires, but does that not promote people black-boxing tools which is already fairly problematic?