Guangbo Chen - 3 months ago 22

R Question

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.

Answer

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
```