# Inverse matrix for contrast coding

I'm trying to understand how "user defined contrast coding" works. My question refers to the example from http://www.ats.ucla.edu/stat/r/library/contrast_coding.htm#User:

#initial contrast matrix including the constant term
mat = matrix(c(1/4, 1/4, 1/4, 1/4, 1, 0, -1, 0, -1/2, 1, 0, -1/2, -1/2, -1/2, 1/2, 1/2), ncol = 4)
mat
[,1] [,2] [,3] [,4]
[1,] 0.25    1 -0.5 -0.5
[2,] 0.25    0  1.0 -0.5
[3,] 0.25   -1  0.0  0.5
[4,] 0.25    0 -0.5  0.5

mymat = solve(t(mat))
mymat
[,1] [,2] [,3] [,4]
[1,]    1 -0.5   -1 -1.5
[2,]    1  0.5    1  0.5
[3,]    1 -1.5   -1 -1.5
[4,]    1  1.5    1  2.5

#remove the intercept (constant) term
my.contrasts<-mymat[,2:4]
contrasts(hsb2$race.f) = my.contrasts  Question: • Why is it necessary to calculate the inverse of the transposed matrix? All other examples on the page doesn't use matrix algebra (e.g "Dummy Coding"). • Inversing a 'contrast coefficient' matrix to obtain a coding matrix is a convenient way and is used for a number of contast types (e.g. deviation, simple, etc.) and not just user-defined contrast type. For dummy coding, inversion just isn't necessary. For polynomial contast - I don't know (see my unanswered question). – ttnphns Sep 5 '13 at 10:35 • Thanks @ttnphns. But why do I have to calculate an extra Coding Matrix, Why is the human readable Contrast Matrix not sufficient? – Thomas Sep 5 '13 at 11:20 • Coding matrix = basis matrix = design matrix shows the values of the set of conrast variables, how they correspond to the categories. Contrast coefficients matrix = L matrix helps to interpret what parameters in the model will mean (represent) statistically. – ttnphns Sep 5 '13 at 11:54 ## 2 Answers [note: for all those people who got here confused after reading section 9 of the UCLA post on contrast matrices, this will help. after hours of head banging, here's what I figured out] The above post is correct. You need to actually do an inverse of the transform. In fact, if you look carefully, that is happening for all the other kinds of contrast coding discussed in that post. I will cover the three most common: dummy, simple, and deviation coding. Please use the following demos to convince yourself of the similarities / difference / relationship between contrasts [as we normally write them for human comprehension] and the thing you see in R [contrast matrix]. First, let look at dummy coding or treatment coding hsb2 = read.table('http://www.ats.ucla.edu/stat/data/hsb2.csv', header=T, sep=",") #creating the factor variable race.f hsb2$race.f = factor(hsb2$race, labels=c("Hispanic", "Asian", "African-Am", "Caucasian")) #================================================================ # =: Dummy Coding [normal intercept] := #================================================================ # This is just a quick way to create what you would normally consider # a simple "treatment" coding or "dummy coding" matrix dummy.coding <- rbind(c(1,-1,-1,-1), c(0, 1, 0, 0), c(0, 0, 1, 0), c(0, 0, 0, 1)) rownames(dummy.coding) <- c("control", "L1","L2","L3") colnames(dummy.coding) <- c("intercept", "L1 vs Control","L2 vs Control","L3 vs Control") # Column 2:4 is what you would normally consider the contrast # And, as you can see, they add to zero dummy.coding # Now, to get the coding matrix that R will use, # you need to take the inverse of the transpose of this matrix # and, drop the first column coding.matrix <- solve(t(dummy.coding))[,-1] coding.matrix # To convince yourself, this is correct, compare it to the # inbuilt R function: contr.treatment(4) # Now, using the dataset that you cited from the UCLA page # You can see the what R is doing under the hood: # First, we assign contrasts(hsb2$race.f) = coding.matrix

# Now, we look at the model matrix
View(cbind(as.character(hsb2$race.f), model.matrix(~race.f, data=hsb2))) # So, essentially, R took that coding matrix and # generated dummy variables # Now, see the linear model: summary(lm(formula = write ~ race.f, data = temp.hsb2))  OK, having done the basic case, lets extend it. In the above example, the intercept of the model was the "control" variable. Notice that the final coding matrix did not include a column for the intercept. That is because the inverse of the transpose of the contrast(dummy.coding) baked it into the final outcome: coding.matrix. Simple Coding So, now, lets look at a case where we want the intercept to represent the grand mean (i.e. mean of means). This is sometimes called simple coding. Here, we just set the first column of the contrast matrix to the same value. #============================================================ #=: Dummy Coding [grand mean intercept i.e. simple coding] := #============================================================ dummy.coding.GM.intercept <- rbind(c(1,-1,-1,-1), c(1, 1, 0, 0), c(1, 0, 1, 0), c(1, 0, 0, 1)) rownames(dummy.coding.GM.intercept) <- c("control", "L1","L2","L3") colnames(dummy.coding.GM.intercept) <- c("intercept: GM", "L1 vs Control","L2 vs Control","L3 vs Control") dummy.coding.GM.intercept coding.matrix <- solve(t(dummy.coding.GM.intercept))[,-1] coding.matrix contrasts(hsb2$race.f) = coding.matrix

# Now, see the linear model and compare the intercepts:
summary(lm(formula = write ~ race.f, data = temp.hsb2))


Deviation Coding or Effects Coding

Finally, lets look at another common case. Here, we want to have contrasts that compare a given level of a factor to the grand mean of the variable. This is sometimes called effects coding, deviation coding, or sum contrasts.

#=======================================================
#     =: Deviation Coding [intercept: grand mean] :=
#=======================================================

deviation.coding <- cbind(c( 0.25,  0.25,  0.25,  0.25),
c( 0.75, -0.25, -0.25, -0.25),
c(-0.25,  0.75, -0.25, -0.25),
c(-0.25, -0.25,  0.75, -0.25))

rownames(deviation.coding)  <- c("L1","L2","L3", "L4")
colnames(deviation.coding)  <- c("intercept: GM", "L1 vs GM","L2 vs GM","L3 vs GM")
deviation.coding

# Now, to get the coding matrix that R will use,
# you need to take the inverse of the transpose of this matrix
# and, drop the first column

coding.matrix <- solve(t(deviation.coding))[,-1]
coding.matrix

# To convince yourself, this is correct, compare it to the
# inbuilt R function:
contr.sum(4)

# Now, using the dataset that you cited from the UCLA page
# You can see the what R is doing under the hood:

# First, we assign
contrasts(hsb2$race.f) = coding.matrix # Now, we look at the model matrix View(cbind(as.character(hsb2$race.f), model.matrix(~race.f, data=hsb2)))

# So, essentially, R took that coding matrix and
# generated variables with EFFECTS CODING


So, there's that. Hope this helps!!

Ok, i think i have an answer. Please note that I'm not a mathematician, so this isn't a prove.

Lets assume, we have collcted a dataset and we want to compare groups.

Our Groups: a, b, c

The comparisons we want to make

• First contrast: a vs b
• Second contrast: b vs c

As an equotation this should look like:

\begin{equation*} c_1 = a - b \\ c_2 = b - c \end{equation*}

As a Matrix: \begin{equation*} \begin{pmatrix} c_1 \\ c_2 \end{pmatrix} = \begin{pmatrix} 1 & -1 & 0\\ 0 & 1 & -1 \end{pmatrix} \cdot \begin{pmatrix} a \\ b \\ c \end{pmatrix} \end{equation*}

Or:

\begin{equation*} c = A \cdot v \end{equation*}

But this aren't the droids we were looking for ;-) What we really want is an equotation like this:

\begin{equation*} v = X \cdot c \end{equation*}

Or:

\begin{equation*} \begin{pmatrix} a \\ b \\ c \end{pmatrix} = \begin{pmatrix} ? & ? \\ ? & ? \\ ? & ? \end{pmatrix} \cdot \begin{pmatrix} c_1 \\ c_2 \end{pmatrix} \end{equation*} We can achieve this by multiply with the inverse Matrix (A'):

\begin{equation*} c = A \cdot v \\ A^{-1} \cdot c = A^{-1} \cdot A \cdot v \\ A^{-1} \cdot c = v \\ v = A^{-1} \cdot c \end{equation*}

So, for our example this would be:

\begin{equation*} \begin{pmatrix} a \\ b \\ c \end{pmatrix} = \begin{pmatrix} 2/3 & 1/3 \\ -1/3 & 1/3 \\ -1/3 & -2/3 \end{pmatrix} \cdot \begin{pmatrix} c_1 \\ c_2 \end{pmatrix} \end{equation*}

Please note, that for taking the inverse of a matrix you need a square matrix! If you haven't a square matrix you (or your pc) has to solve the problem numerically. In r this can be done with the function ginv() from the package MASS