是否可以在保持简化符号的同时更新模型 object 的公式?
Is it possible to update the formula of a model object while maintaining simplified notation?
我有一个包含一些交互项的模型公式。当我通过 update()
更新模型时,*
运算符被删除,取而代之的是扩展的 x + y + x:y
形式。这不是什么大问题,但是当通过 anova()
(或其他地方)比较模型时,它往往会使模型公式在视觉上不那么可口,并且会更改 anova
object 的标题不方便
问题是 terms.formula()
(通过 update.formula()
)似乎并不容易强制简化公式(应该通过简化选项?)。
例如:
# Looking for Dep ~ Ind1 * Ind2 + Ind3
update.formula(Dep ~ Ind1 * Ind2, . ~ . + Ind3)
##Dep ~ Ind1 + Ind2 + Ind3 + Ind1:Ind2
也许通过 simplify = TRUE
就可以了?
update.formula(Dep ~ Ind1 * Ind2, . ~ . + Ind3, simplify = TRUE)
##Dep ~ Ind1 + Ind2 + Ind3 + Ind1:Ind2
或者条款得到 re-ordered,这会阻止它返回简化版本?
update.formula(Dep ~ Ind1 * Ind2, . ~ . + Ind3, simplify = TRUE, keep.order = TRUE)
##Dep ~ Ind1 + Ind2 + Ind3 + Ind1:Ind2
我目前使用的解决方法是只适合一个新模型,当模型调用需要多个附加参数时,这不太方便。是否有更好的解决方案来更新公式 object,同时保持简化的 *
表示法?
稍微清晰一点的用例(全因子设计):
i1 <- sample(c("A", "B"), 100, replace = TRUE)
i2 <- sample(c("C", "D"), 100, replace = TRUE)
i3 <- sample(c("E", "F"), 100, replace = TRUE)
i4 <- sample(c("G", "H"), 100, replace = TRUE)
d1 <- rnorm(100)
df <- data.frame(d1, i1, i2, i3, i4)
m1 <- lm(d1 ~ i1 * i2 * i3, data = df)
m2 <- update(m1, formula = . ~ . * i4)
m2s <- lm(d1 ~ i1 * i2 * i3 * i4, data = df) # Explicitly declare new model
anova(m1, m2)
##Analysis of Variance Table
##Model 1: d1 ~ i1 * i2 * i3
##Model 2: d1 ~ i1 + i2 + i3 + i4 + i1:i2 + i1:i3 + i2:i3 + i1:i4 + i2:i4 +
## i3:i4 + i1:i2:i3 + i1:i2:i4 + i1:i3:i4 + i2:i3:i4 + i1:i2:i3:i4
## Res.Df RSS Df Sum of Sq F Pr(>F)
##1 92 121.07
##2 84 118.70 8 2.3646 0.2092 0.9885
anova(m1, m2s)
##Analysis of Variance Table
##Model 1: d1 ~ i1 * i2 * i3
##Model 2: d1 ~ i1 * i2 * i3 * i4
## Res.Df RSS Df Sum of Sq F Pr(>F)
##1 92 121.07
##2 84 118.70 8 2.3646 0.2092 0.9885
simplify
in terms.formula
与您认为的相反。您实际上想要 simplify = FALSE
,但使用默认值 stats::update.formula
无法做到这一点。这是一个可以满足您需求的版本。请注意,默认方法刚刚更改为使用我的 update_no_simplify.formula 版本,公式方法刚刚更改为使用 simplify = FALSE:
update_no_simplify <- function(object, ...) {
UseMethod("update_no_simplify")
}
update_no_simplify.formula <- function(old, new) {
tmp <- .Call(stats:::C_updateform, as.formula(old), as.formula(new))
formula(terms.formula(tmp, simplify = FALSE))
}
update_no_simplify.default <- function (object, formula., ..., evaluate = TRUE) {
if (is.null(call <- getCall(object)))
stop("need an object with call component")
extras <- match.call(expand.dots = FALSE)$...
if (!missing(formula.))
call$formula <- update_no_simplify.formula(formula(object), formula.)
if (length(extras)) {
existing <- !is.na(match(names(extras), names(call)))
for (a in names(extras)[existing]) call[[a]] <- extras[[a]]
if (any(!existing)) {
call <- c(as.list(call), extras[!existing])
call <- as.call(call)
}
}
if (evaluate)
eval(call, parent.frame())
else call
}
m3 <- update_no_simplify(m1, . ~ . * i4)
anova(m1, m3)
输出:
##Analysis of Variance Table
##
##Model 1: d1 ~ i1 * i2 * i3
##Model 2: d1 ~ i1 * i2 * i3 * i4
## Res.Df RSS Df Sum of Sq F Pr(>F)
##1 92 95.496
##2 84 89.193 8 6.3032 0.742 0.6542
我有一个包含一些交互项的模型公式。当我通过 update()
更新模型时,*
运算符被删除,取而代之的是扩展的 x + y + x:y
形式。这不是什么大问题,但是当通过 anova()
(或其他地方)比较模型时,它往往会使模型公式在视觉上不那么可口,并且会更改 anova
object 的标题不方便
问题是 terms.formula()
(通过 update.formula()
)似乎并不容易强制简化公式(应该通过简化选项?)。
例如:
# Looking for Dep ~ Ind1 * Ind2 + Ind3
update.formula(Dep ~ Ind1 * Ind2, . ~ . + Ind3)
##Dep ~ Ind1 + Ind2 + Ind3 + Ind1:Ind2
也许通过 simplify = TRUE
就可以了?
update.formula(Dep ~ Ind1 * Ind2, . ~ . + Ind3, simplify = TRUE)
##Dep ~ Ind1 + Ind2 + Ind3 + Ind1:Ind2
或者条款得到 re-ordered,这会阻止它返回简化版本?
update.formula(Dep ~ Ind1 * Ind2, . ~ . + Ind3, simplify = TRUE, keep.order = TRUE)
##Dep ~ Ind1 + Ind2 + Ind3 + Ind1:Ind2
我目前使用的解决方法是只适合一个新模型,当模型调用需要多个附加参数时,这不太方便。是否有更好的解决方案来更新公式 object,同时保持简化的 *
表示法?
稍微清晰一点的用例(全因子设计):
i1 <- sample(c("A", "B"), 100, replace = TRUE)
i2 <- sample(c("C", "D"), 100, replace = TRUE)
i3 <- sample(c("E", "F"), 100, replace = TRUE)
i4 <- sample(c("G", "H"), 100, replace = TRUE)
d1 <- rnorm(100)
df <- data.frame(d1, i1, i2, i3, i4)
m1 <- lm(d1 ~ i1 * i2 * i3, data = df)
m2 <- update(m1, formula = . ~ . * i4)
m2s <- lm(d1 ~ i1 * i2 * i3 * i4, data = df) # Explicitly declare new model
anova(m1, m2)
##Analysis of Variance Table
##Model 1: d1 ~ i1 * i2 * i3
##Model 2: d1 ~ i1 + i2 + i3 + i4 + i1:i2 + i1:i3 + i2:i3 + i1:i4 + i2:i4 +
## i3:i4 + i1:i2:i3 + i1:i2:i4 + i1:i3:i4 + i2:i3:i4 + i1:i2:i3:i4
## Res.Df RSS Df Sum of Sq F Pr(>F)
##1 92 121.07
##2 84 118.70 8 2.3646 0.2092 0.9885
anova(m1, m2s)
##Analysis of Variance Table
##Model 1: d1 ~ i1 * i2 * i3
##Model 2: d1 ~ i1 * i2 * i3 * i4
## Res.Df RSS Df Sum of Sq F Pr(>F)
##1 92 121.07
##2 84 118.70 8 2.3646 0.2092 0.9885
simplify
in terms.formula
与您认为的相反。您实际上想要 simplify = FALSE
,但使用默认值 stats::update.formula
无法做到这一点。这是一个可以满足您需求的版本。请注意,默认方法刚刚更改为使用我的 update_no_simplify.formula 版本,公式方法刚刚更改为使用 simplify = FALSE:
update_no_simplify <- function(object, ...) {
UseMethod("update_no_simplify")
}
update_no_simplify.formula <- function(old, new) {
tmp <- .Call(stats:::C_updateform, as.formula(old), as.formula(new))
formula(terms.formula(tmp, simplify = FALSE))
}
update_no_simplify.default <- function (object, formula., ..., evaluate = TRUE) {
if (is.null(call <- getCall(object)))
stop("need an object with call component")
extras <- match.call(expand.dots = FALSE)$...
if (!missing(formula.))
call$formula <- update_no_simplify.formula(formula(object), formula.)
if (length(extras)) {
existing <- !is.na(match(names(extras), names(call)))
for (a in names(extras)[existing]) call[[a]] <- extras[[a]]
if (any(!existing)) {
call <- c(as.list(call), extras[!existing])
call <- as.call(call)
}
}
if (evaluate)
eval(call, parent.frame())
else call
}
m3 <- update_no_simplify(m1, . ~ . * i4)
anova(m1, m3)
输出:
##Analysis of Variance Table
##
##Model 1: d1 ~ i1 * i2 * i3
##Model 2: d1 ~ i1 * i2 * i3 * i4
## Res.Df RSS Df Sum of Sq F Pr(>F)
##1 92 95.496
##2 84 89.193 8 6.3032 0.742 0.6542