1
$\begingroup$

According to Wikipedia, contrast is defined as follows:

Let $\theta_1$,$\ldots$,$\theta_t$ be a set of variables, either parameters or statistics, and $a_1$,$\ldots$,$a_t$ be known constants. The quantity $\sum_{i=1}^t a_i \theta_i$ is a linear combination. It is called a contrast if $\sum_{i=1}^t a_i = 0.$

However, if you try to use contrasts function in R, you get following:

> require(readr)
> hsb2 <- read_csv("http://www.ats.ucla.edu/stat/data/hsb2.csv")
> hsb2$race.f <- factor(hsb2$race, labels=c("Hispanic", "Asian", "African-Am", "Caucasian"))
> contrasts(hsb2$race.f)
           Asian African-Am Caucasian
Hispanic       0          0         0
Asian          1          0         0
African-Am     0          1         0
Caucasian      0          0         1

In other words, both marginal sums do not equal to 0. Why?

$\endgroup$

2 Answers 2

3
$\begingroup$

This depends on the context in which you are using contrasts. contrasts in R is generally used to define contrasts for factors, but is not used in ANOVA or regression. For that, there are different type of contrast methods -- see ?contr.sum for the help function and the other possibilities of contr.*. The wikipedia snippet only covers one type of specific contrast, if you would like to generate this in R, use the contr.sum function which ensures that the contrasts sum to zero.

$\endgroup$
1
$\begingroup$

[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]

Please use the following demos to convince yourself of the similarities / difference / relationship between contrasts [sometimes called design matrices?] and the thing you see in R [contrast matrix].

In essence, R uses the contrast matrix to generate "dummy variables" that represent the factor in the model. You need to convert the contrasts into an appropriate coding matrix.

Please use the following code to convince yourself of the relationship between the two:

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 matrix (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!!

$\endgroup$
1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.