我不想要主效果,因为它与更精细的因子固定效果共线,所以有这些NA
很烦人。
在这个例子中:
lm(y ~ x * z)
我想要x
(数字)和z
(因素)的互动,而不是z
的主要效果。
答案 0 :(得分:6)
?formula
的R文档说:
'*'运算符表示因子交叉:'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
和b
的变量类。
这种行为是由一个名为model.matrix.default
的神奇函数引起的,它从公式构造一个设计矩阵。数值变量仅包含在列中,但因子变量自动编码为多个虚拟列。正是这种虚拟重新编码是一种魔力。通常认为我们可以启用或禁用对比来控制它,但不是真的。即使在this simplest example,我们也无法控制对比。问题是model.matrix.default
在进行虚拟编码时有自己的规则,并且对指定模型公式的方式非常敏感。正是由于这个原因,当两个因素之间存在相互作用时,我们才能放弃主效应。
根据您的问题,x
是数字,z
是一个因素。您可以指定具有交互的模型,但不能通过
z
的主效应
y ~ x + x:z
由于x
是数字,因此等同于执行
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
被对比,因此它的第一级&#34; a&#34;不是虚拟编码,而在第二个规范中,z
没有对比,并且两个级别都是&#34; a&#34;和&#34; b&#34;是虚拟编码的。鉴于两个规范都以三个系数结束,它们实际上是等价的(从数学上讲,两种情况下的设计矩阵具有相同的列空间),您可以通过比较它们的拟合值来验证这一点:
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
没有对比?因为如果是的话,我们就会失去水平&#34; a&#34;在构建交互时。即使你需要对比,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
。它能够做出正确的决定!
让我重申一下:当互动存在时,没有办法放弃主要效果。
我不会在这里提供额外的例子,因为我在Why do I get NA coefficients and how does lm
drop reference level for interaction中有一个例子。请参阅&#34;对比互动&#34;那边的部分。简而言之,以下所有规格都给出了相同的模型(它们具有相同的拟合值):
~ year:treatment
~ year:treatment + 0
~ year + year:treatment
~ treatment + year:treatment
~ year + treatment + year:treatment
~ year * treatment
特别是,第一个规范导致NA
系数。
因此,一旦~
的RHS包含year:treatment
,您就永远不会要求model.matrix.default
放弃主要效果。
People inexperienced with this behavior are to be surprised when producing ANOVA tables
model.matrix.default
有些人认为model.matrix.default
很烦人,因为在虚拟编码中似乎没有一致的方式。 A&#34;一致的方式&#34;在他们看来,总是放弃第一个因素水平。好吧,没问题,您可以通过手动执行虚拟编码来绕过model.matrix.default
,并将生成的虚拟矩阵作为变量提供给lm
等。
但是,您仍需要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
中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
And the latter case is probably what contefranz is trying to do
但是,我并不真的推荐这种黑客攻击。当您将模型公式传递给lm
等时,model.matrix.default
会尝试为您提供最明智的构造。而且,实际上我们想用拟合模型进行预测。如果您自己进行了虚拟编码,那么在向newdata
提供predict
时您会遇到困难。
答案 1 :(得分:2)
这是一个非常好的解释,但在选择重要预测因子的过程中,让我再添加一件事。
让我们再考虑以下模型:
fit1 <- lm(y ~ x + x:z)
#Coefficients:
#(Intercept) x x:zb
# 0.1989 -0.1627 -0.5456
假设主效果x
没有统计意义,你想摆脱它。至少对我来说,最直观的是写上面的第二个模型:
fit2 <- lm(y ~ x:z)
#Coefficients:
#(Intercept) x:za x:zb
# 0.1989 -0.1627 -0.7082
最终将掩盖的主效应作为与因子基线水平的相互作用。现在,我能够找到的唯一解决方案是为了真正不包含主要效果,就是利用lm.fit
,正如大家所知,它不会返回类lm
的对象,而是list
1}}。所以问题是:你知道任何摆脱主效应而不失去lm
类的方法吗?
答案 2 :(得分:1)
使用lm.fit但获得lm类对象: 我不是程序员,但对lm函数的简单改编对我有用:我添加了lm.fit所需的两个参数(模型矩阵和响应变量),并替换了(在lm函数中)x和y(用于lm中的lm.fit)由我的模型矩阵Xmat和响应:
a_list[!grepl("a",names(a_list))]
然后,照常创建模型矩阵,但是删除不需要的列:
lm.2 <- function (formula, data, subset, weights, na.action, method = "qr",
model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE,
contrasts = NULL, offset, ..., Xmat=NA, response=NA)
{
ret.x <- x
ret.y <- y
cl <- match.call()
mf <- match.call(expand.dots = FALSE)
m <- match(c("formula", "data", "subset", "weights", "na.action",
"offset"), names(mf), 0L)
mf <- mf[c(1L, m)]
mf$drop.unused.levels <- TRUE
mf[[1L]] <- quote(stats::model.frame)
mf <- eval(mf, parent.frame())
if (method == "model.frame")
return(mf)
else if (method != "qr")
warning(gettextf("method = '%s' is not supported. Using 'qr'",
method), domain = NA)
mt <- attr(mf, "terms")
y <- model.response(mf, "numeric")
w <- as.vector(model.weights(mf))
if (!is.null(w) && !is.numeric(w))
stop("'weights' must be a numeric vector")
offset <- as.vector(model.offset(mf))
if (!is.null(offset)) {
if (length(offset) != NROW(y))
stop(gettextf("number of offsets is %d, should equal %d (number of observations)",
length(offset), NROW(y)), domain = NA)
}
if (is.empty.model(mt)) {
x <- NULL
z <- list(coefficients = if (is.matrix(y)) matrix(NA_real_,
0, ncol(y)) else numeric(), residuals = y, fitted.values = 0 *
y, weights = w, rank = 0L, df.residual = if (!is.null(w)) sum(w !=
0) else if (is.matrix(y)) nrow(y) else length(y))
if (!is.null(offset)) {
z$fitted.values <- offset
z$residuals <- y - offset
}
}
else {
z <- if (is.null(w))
lm.fit(Xmat, response, offset = offset, singular.ok = singular.ok,
...)
else lm.wfit(Xmat, response, w, offset = offset, singular.ok = singular.ok,
...)
}
class(z) <- c(if (is.matrix(y)) "mlm", "lm")
z$na.action <- attr(mf, "na.action")
z$offset <- offset
z$contrasts <- attr(x, "contrasts")
z$xlevels <- .getXlevels(mt, mf)
z$call <- cl
z$terms <- mt
if (model)
z$model <- mf
if (ret.x)
z$x <- x
if (ret.y)
z$y <- y
if (!qr)
z$qr <- NULL
z
}
当然,所有这些都可以进一步详细说明,但是对我来说,它确实有效->它返回一个lm对象,可以将其与summary,resid,sim,plot一起使用...
最佳 庇护