Guangbo Chen - 2 months ago 16
R Question

How to set contrasts for my variable in regression analysis with R?

During coding, I need to change the dummy value assigned to a factor. However, the following code does not work. Any suggestion?

``````test_mx= data.frame(a= c(T,T,T,F,F,F), b= c(1,1,1,0,0,0))
test_mx
a b
1  TRUE 1
2  TRUE 1
3  TRUE 1
4 FALSE 0
5 FALSE 0
6 FALSE 0

model= glm(b ~ a, data= test_mx, family= "binomial")
summary(model)

model= glm(a ~ b, data= test_mx, family= "binomial")
summary(model)
``````

Here I will get the coef for b is 47. Now if I swap the dummy value, it should be -47 then. However, this is not the case.

``````test_mx2= test_mx
contrasts(test_mx2\$a)
TRUE
FALSE    0
TRUE     1
contrasts(test_mx2\$a) = c(1,0)
contrasts(test_mx2\$a)
[,1]
FALSE    1
TRUE     0
model= glm(a ~ b, data= test_mx2, family= "binomial")
summary(model)
``````

coef for b is still the same. What is going on? Thanks.

There are several confusing things regarding your question. You have used both `a ~ b` and `b ~ a`, so what are you looking at exactly?

• Contrasts only applies to covariates / independent variables, as it is related to construction of model matrix; So for `a ~ b`, contrasts should be applied to `b`, while for `b ~ a`, contrasts should be applied to `a`;
• Contrasts only works for factor / logical variables, rather than numerical variables. So unless you have `b` as a factor, you can't play contrasts with it.

Without changing data type, it is clear that only a model `b ~ a` is legitimate for further discussion. In the following, I will show how to set contrasts for `a`.

Method 1: using `contrasts` argument of `glm` and `lm`

We can control contrasts treatment by the `contrasts` argument of `glm` (the same for `lm`):

``````## dropping the first factor level (default)
coef(glm(b ~ a, data = test_mx, family = binomial(),
contrasts = list(a = contr.treatment(n = 2, base = 1))))
#(Intercept)          a2
#  -24.56607    49.13214

## dropping the second factor level
coef(glm(b ~ a, data = test_mx, family = binomial(),
contrasts = list(a = contr.treatment(n = 2, base = 2))))
#(Intercept)          a1
#   24.56607   -49.13214
``````

Here, `contr.treatment` is generating a contrasts matrix:

``````contr.treatment(n = 2, base = 1)
#  2
#1 0
#2 1

contr.treatment(n = 2, base = 2)
#  1
#1 1
#2 0
``````

and they are passed to `glm` to effectively change the behaviour of `model.matrix.default`. Let's compare the model matrix for two cases:

``````model.matrix.default( ~ a, test_mx, contrasts.arg =
list(a = contr.treatment(n = 2, base = 1)))

#  (Intercept) a2
#1           1  1
#2           1  1
#3           1  1
#4           1  0
#5           1  0
#6           1  0

model.matrix.default( ~ a, test_mx, contrasts.arg =
list(a = contr.treatment(n = 2, base = 2)))

#  (Intercept) a1
#1           1  0
#2           1  0
#3           1  0
#4           1  1
#5           1  1
#6           1  1
``````

The second column for `a` is just a flip between `0` and `1`, which is what you have expected for a dummy variable.

Method 2: setting "contrasts" attribute to data frame directly

We can use `C` or `contrasts` to set "contrasts" attributes (`C` is only for setting, but `contrasts` can be used for viewing as well):

``````test_mx2 <- test_mx
contrasts(test_mx2\$a) <- contr.treatment(n = 2, base = 1)
str(test_mx2)
#'data.frame':  6 obs. of  2 variables:
# \$ a: Factor w/ 2 levels "FALSE","TRUE": 2 2 2 1 1 1
#  ..- attr(*, "contrasts")= num [1:2, 1] 0 1
#  .. ..- attr(*, "dimnames")=List of 2
#  .. .. ..\$ : chr  "FALSE" "TRUE"
#  .. .. ..\$ : chr "2"
# \$ b: num  1 1 1 0 0 0

test_mx3 <- test_mx
contrasts(test_mx3\$a) <- contr.treatment(n = 2, base = 2)
str(test_mx3)
#'data.frame':  6 obs. of  2 variables:
# \$ a: Factor w/ 2 levels "FALSE","TRUE": 2 2 2 1 1 1
#  ..- attr(*, "contrasts")= num [1:2, 1] 1 0
#  .. ..- attr(*, "dimnames")=List of 2
#  .. .. ..\$ : chr  "FALSE" "TRUE"
#  .. .. ..\$ : chr "1"
# \$ b: num  1 1 1 0 0 0
``````

Now we can fit `glm` without using `contrasts` argument:

``````coef(glm(b ~ a, data = test_mx2, family = "binomial"))
#(Intercept)          a2
#  -24.56607    49.13214

coef(glm(b ~ a, data = test_mx3, family = "binomial"))
#(Intercept)          a1
#   24.56607   -49.13214
``````

Method 3: setting `options("contrasts")` for a global change

Hahaha, @BenBolker yet mentions another option, which is by setting the global options of R. For your specific example with a factor involving only two levels, we can makes use of `?contr.SAS`.

``````## using R default contrasts options
#\$contrasts
#        unordered           ordered
#"contr.treatment"      "contr.poly"

coef(glm(b ~ a, data = test_mx, family = "binomial"))
#(Intercept)       aTRUE
#  -24.56607    49.13214

options(contrasts = c("contr.SAS", "contr.poly"))
coef(glm(b ~ a, data = test_mx, family = "binomial"))
#(Intercept)      aFALSE
#   24.56607   -49.13214
``````

But I believe Ben is just mention this to complete the picture; He will not take this way in reality, as changing global options is not good for getting reproducible R code.

Another issue is that `contr.SAS` will just treat the last factor level as reference. In your particular case with only 2 levels, this effectively does the "flipping".

Method 4: Manually recoding your factor levels

I had no intention to mention this as it is so trivial, but since I have added "Method 3", I'd better add this one, too.

``````test_mx4 <- test_mx
test_mx4\$a <- factor(test_mx4\$a, levels = c("TRUE", "FALSE"))
coef(glm(b ~ a, data = test_mx4, family = "binomial"))
#(Intercept)       aTRUE
#  -24.56607    49.13214

test_mx5 <- test_mx
test_mx5\$a <- factor(test_mx5\$a, levels = c("FALSE", "TRUE"))
coef(glm(b ~ a, data = test_mx5, family = "binomial"))
#(Intercept)      aFALSE
#   24.56607   -49.13214
``````