介绍
R 文档?formula
says:
“*”运算符表示因子交叉:“a * b”解释为“a + b + a : b”
因此,听起来似乎删除主要效果很简单,只需执行以下操作之一即可:
a + a:b ## main effect on `b` is dropped
b + a:b ## main effect on `a` is dropped
a:b ## main effects on both `a` and `b` are dropped
哦真的吗?不不不 (太简单,太天真)。实际上,这取决于变量类别a
and b
.
- 如果它们都不是因素,或者只有一个是因素,则这是真的;
- 如果两者都是因素,那就不是。当存在交互作用(高阶效应)时,你永远不能放弃主效应(低阶效应)。
这种行为是由于一个名为的神奇函数model.matrix.default
,它根据公式构造设计矩阵。数值变量只是按原样包含在列中,但因子变量会自动编码为许多虚拟列。正是这种虚拟的重新编码才具有魔力。人们普遍认为我们可以启用或禁用对比度来控制它,但事实并非如此。即使在这个最简单的例子 https://stackoverflow.com/q/38150773/4891738。问题是model.matrix.default
在进行虚拟编码时有自己的规则,并且对您如何指定模型公式非常敏感。正是由于这个原因,当两个因素之间存在交互作用时,我们不能丢弃主效应。
数字和因子之间的相互作用
从你的问题来看,x
是数字并且z
是一个因素。您可以指定具有交互作用的模型,但不能指定具有主效应的模型z
by
y ~ x + x:z
Since x
是数字,相当于 do
y ~ x:z
这里唯一的区别是参数化(或者如何model.matrix.default
进行虚拟编码)。考虑一个小例子:
set.seed(0)
y <- rnorm(10)
x <- rnorm(10)
z <- gl(2, 5, labels = letters[1:2])
fit1 <- lm(y ~ x + x:z)
#Coefficients:
#(Intercept) x x:zb
# 0.1989 -0.1627 -0.5456
fit2 <- lm(y ~ x:z)
#Coefficients:
#(Intercept) x:za x:zb
# 0.1989 -0.1627 -0.7082
从系数的名称我们可以看出,在第一个规范中,z
进行对比,因此其第一级“a”不是虚拟编码,而在第二个规范中,z
不进行对比,并且级别“a”和“b”都是虚拟编码的。鉴于这两个规范最终都有三个系数,它们实际上是等效的(从数学上讲,两种情况下的设计矩阵具有相同的列空间),您可以通过比较它们的拟合值来验证这一点:
all.equal(fit1$fitted, fit2$fitted)
# [1] TRUE
那么为什么是z
与第一种情况对比?因为否则我们有两个虚拟列x:z
,这两列的总和就是x
,与现有模型项别名x
在公式。事实上,在这种情况下即使你要求你不想要对比,model.matrix.default
不会服从:
model.matrix.default(y ~ x + x:z,
contrast.arg = list(z = contr.treatment(nlevels(z), contrasts = FALSE)))
# (Intercept) x x:zb
#1 1 0.7635935 0.0000000
#2 1 -0.7990092 0.0000000
#3 1 -1.1476570 0.0000000
#4 1 -0.2894616 0.0000000
#5 1 -0.2992151 0.0000000
#6 1 -0.4115108 -0.4115108
#7 1 0.2522234 0.2522234
#8 1 -0.8919211 -0.8919211
#9 1 0.4356833 0.4356833
#10 1 -1.2375384 -1.2375384
那么为什么在第二种情况下是z
不对比?因为如果是这样,我们在构建交互时就会失去“a”级的效果。即使你需要对比,model.matrix.default
只会忽略你:
model.matrix.default(y ~ x:z,
contrast.arg = list(z = contr.treatment(nlevels(z), contrasts = TRUE)))
# (Intercept) x:za x:zb
#1 1 0.7635935 0.0000000
#2 1 -0.7990092 0.0000000
#3 1 -1.1476570 0.0000000
#4 1 -0.2894616 0.0000000
#5 1 -0.2992151 0.0000000
#6 1 0.0000000 -0.4115108
#7 1 0.0000000 0.2522234
#8 1 0.0000000 -0.8919211
#9 1 0.0000000 0.4356833
#10 1 0.0000000 -1.2375384
哦,太棒了model.matrix.default
。它能够做出正确的决定!
两个因素之间的相互作用
让我重申一下:当存在交互时,无法消除主效应。
我不会在这里提供额外的例子,因为我在为什么我会得到 NA 系数以及如何得到lm降低交互参考电平 https://stackoverflow.com/q/40723196/4891738。请参阅那里的“交互对比”部分。简而言之,以下所有规格都给出相同的模型(它们具有相同的拟合值):
~ year:treatment
~ year:treatment + 0
~ year + year:treatment
~ treatment + year:treatment
~ year + treatment + year:treatment
~ year * treatment
特别是,第一个规范导致NA
系数。
所以一旦 RHS~
包含一个year:treatment
,你永远不能问model.matrix.default
降低主效应。
.
通过传递model.matrix.default
有些人认为model.matrix.default
令人烦恼的是,它在虚拟编码中似乎没有一致的方式。他们认为“一致的方式”是始终降低第一个因素水平。嗯,没问题,可以绕过model.matrix.default
通过手动进行虚拟编码,并将生成的虚拟矩阵作为变量提供给lm
, etc.
然而,你仍然需要model.matrix.default
帮助轻松进行虚拟编码a(是的,只有一个)因素变量。例如,对于变量z
在我们前面的示例中,其完整的虚拟编码如下,您可以保留其全部或部分列进行回归。
Z <- model.matrix.default(~ z + 0) ## no contrasts (as there is no intercept)
# za zb
#1 1 0
#2 1 0
#3 1 0
#4 1 0
#5 1 0
#6 0 1
#7 0 1
#8 0 1
#9 0 1
#10 0 1
#attr(,"assign")
#[1] 1 1
#attr(,"contrasts")
#attr(,"contrasts")$z
#[1] "contr.treatment"
回到我们的简单示例,如果我们不想进行对比z
in y ~ x + x:z
, 我们可以做的
Z2 <- Z[, 1:2] ## use "[" to remove attributes of `Z`
lm(y ~ x + x:Z2)
#Coefficients:
#(Intercept) x x:Z2za x:Z2zb
# 0.1989 -0.7082 0.5456 NA
毫不奇怪,我们看到NA
(因为colSums(Z2)
别名为x
)。如果我们想加强对比y ~ x:z
,我们可以执行以下任一操作:
Z1 <- Z[, 1]
lm(y ~ x:Z1)
#Coefficients:
#(Intercept) x:Z1
# 0.34728 -0.06571
Z1 <- Z[, 2]
lm(y ~ x:Z1)
#Coefficients:
#(Intercept) x:Z1
# 0.2318 -0.6860
后一种情况可能就是这样对抗正在尝试做 https://stackoverflow.com/a/42028278/4891738.
然而,我真的不推荐这种黑客行为。当您将模型公式传递给lm
, etc, model.matrix.default
试图给您最合理的构建。此外,实际上我们希望使用拟合模型进行预测。如果您自己完成了虚拟编码,那么在提供时会遇到困难newdata
to predict
.