R有一个方便的工具来操纵公式,update.formula()
。当你想得到类似于"公式的公式包含以前公式中除x
"之外的所有术语,例如
f1 <- z ~ a + b + c
(f2 <- update.formula(f1, . ~ . - c))
## z ~ a + b
但是,这似乎不适用于抵消条款:
f3 <- z ~ a + offset(b)
update(f3, . ~ . - offset(b))
## z ~ a + offset(b)
我已经挖掘到terms.formula
,?update.formula
引用:
[替换之后,...]结果然后简化为 via 'terms.formula(simplify = TRUE)'。
terms.formula(z ~ a + offset(b) - offset(b), simplify=TRUE)
## z ~ a + offset(b)
(即,这似乎不会删除offset(b)
...)
我知道我可以通过使用deparse()
和文本处理来解决问题,或者通过递归处理公式来删除我不想要的术语,但这些解决方案很丑陋和/或讨厌实施。无论是为什么这不起作用的启示,还是一个相当紧凑的解决方案,都会很棒......
答案 0 :(得分:7)
1)递归以offset(...)
替换offset
的公式递归下移,然后使用offset
删除update
。没有进行字符串操作,虽然它确实需要多行代码,但它仍然相当短,并且删除了单个和多个offset
项。
如果存在多个偏移量,则可以通过设置preserve
来保留其中一些偏移量,例如,如果preserve = 2
则保留第二个偏移量并删除其他任何偏移量。默认设置是保留none,即全部删除它们。
no.offset <- function(x, preserve = NULL) {
k <- 0
proc <- function(x) {
if (length(x) == 1) return(x)
if (x[[1]] == as.name("offset") && !((k<<-k+1) %in% preserve)) return(x[[1]])
replace(x, -1, lapply(x[-1], proc))
}
update(proc(x), . ~ . - offset)
}
# tests
no.offset(z ~ a + offset(b))
## z ~ a
no.offset(z ~ a + offset(b) + offset(c))
## z ~ a
请注意,如果您不需要
preserve
参数,那么该行 初始化k
可以省略,if
简化为:if (x[[1]] == as.name("offset")) return(x[[1]])
2)术语这既不直接使用字符串操作也不使用递归。首先获取terms
对象,删除其offset
属性并使用我们从fixFormulaObject
的内容中提取的terms.formula
进行修复。通过将fixFormulaObject
的源代码复制到您的源代码并删除下面的eval
行,可以减少这一点。 preserve
的行为与(1)相同。
no.offset2 <- function(x, preserve = NULL) {
tt <- terms(x)
attr(tt, "offset") <- if (length(preserve)) attr(tt, "offset")[preserve]
eval(body(terms.formula)[[2]]) # extract fixFormulaObject
f <- fixFormulaObject(tt)
environment(f) <- environment(x)
f
}
# tests
no.offset2(z ~ a + offset(b))
## z ~ a
no.offset2(z ~ a + offset(b) + offset(c))
## z ~ a
请注意,如果您不需要
preserve
参数,则表示该行 zaps偏移属性可以简化为:attr(tt, "offset") <- NULL
答案 1 :(得分:4)
这似乎是设计上的。但一个简单的解决方法是
offset2 = offset
f3 <- z ~ a + offset2(b)
update(f3, . ~ . - offset2(b))
# z ~ a
如果您需要灵活地接受做包含offset()
的公式,例如,如果公式是由可能不知道需要使用{{1}的软件包用户提供的代替offset2
,我们还应添加一行来更改传入公式中offset
的所有实例:
offset()