从公式中删除偏移项
removing offset terms from a formula
R 有一个操作公式的便捷工具,update.formula()
。当你想得到类似 "formula containing all terms in previous formula except 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
引用:
[after substituting, ...] The result is then simplified via ‘terms.formula(simplify = TRUE)’.
terms.formula(z ~ a + offset(b) - offset(b), simplify=TRUE)
## z ~ a + offset(b)
(即,这似乎没有删除 offset(b)
...)
我知道我可以通过使用 deparse()
和文本处理来破解解决方案,或者通过递归处理公式以删除我不想要的术语,但这些解决方案很难看 and/or 实施起来很烦人。关于 为什么 这不起作用的启示,或者一个相当紧凑的解决方案,都会很棒 ...
这似乎是设计使然。但一个简单的解决方法是
offset2 = offset
f3 <- z ~ a + offset2(b)
update(f3, . ~ . - offset2(b))
# z ~ a
如果您需要灵活地接受 do 包括 offset()
的公式,例如,如果公式是由可能不知道需要的软件包用户提供的要使用 offset2
代替 offset
,那么我们还应该添加一行来更改传入公式中 offset()
的任何实例:
f3 <- z ~ a + offset(b)
f4 <- as.formula(gsub("offset\(", "offset2(", deparse(f3)))
f4 <- update(f4, . ~ . - offset2(b))
# finally, just in case there are any references to offset2 remaining, we should revert them back to offset
f4 <- as.formula(gsub("offset2\(", "offset(", deparse(f4)))
# z ~ a
1) 递归 通过将offset(...)
替换为offset
的公式递归下降,然后使用update
删除offset
。没有进行任何字符串操作,尽管它确实需要多行代码,但它仍然相当短,并且确实删除了单个和多个 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
Note that if you don't need the preserve
argument then the line
initializing k
can be omitted and the if
simplified to:
if (x[[1]] == as.name("offset")) return(x[[1]])
2) terms 这既不直接使用字符串操作也不使用递归。首先获取 terms
对象,删除它的 offset
属性并使用我们从 terms.formula
中提取的 fixFormulaObject
修复它。通过将 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
Note that if you don't need the preserve
argument then the line that
zaps the offset attribute can be simplified to:
attr(tt, "offset") <- NULL
R 有一个操作公式的便捷工具,update.formula()
。当你想得到类似 "formula containing all terms in previous formula except 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
引用:
[after substituting, ...] The result is then simplified via ‘terms.formula(simplify = TRUE)’.
terms.formula(z ~ a + offset(b) - offset(b), simplify=TRUE)
## z ~ a + offset(b)
(即,这似乎没有删除 offset(b)
...)
我知道我可以通过使用 deparse()
和文本处理来破解解决方案,或者通过递归处理公式以删除我不想要的术语,但这些解决方案很难看 and/or 实施起来很烦人。关于 为什么 这不起作用的启示,或者一个相当紧凑的解决方案,都会很棒 ...
这似乎是设计使然。但一个简单的解决方法是
offset2 = offset
f3 <- z ~ a + offset2(b)
update(f3, . ~ . - offset2(b))
# z ~ a
如果您需要灵活地接受 do 包括 offset()
的公式,例如,如果公式是由可能不知道需要的软件包用户提供的要使用 offset2
代替 offset
,那么我们还应该添加一行来更改传入公式中 offset()
的任何实例:
f3 <- z ~ a + offset(b)
f4 <- as.formula(gsub("offset\(", "offset2(", deparse(f3)))
f4 <- update(f4, . ~ . - offset2(b))
# finally, just in case there are any references to offset2 remaining, we should revert them back to offset
f4 <- as.formula(gsub("offset2\(", "offset(", deparse(f4)))
# z ~ a
1) 递归 通过将offset(...)
替换为offset
的公式递归下降,然后使用update
删除offset
。没有进行任何字符串操作,尽管它确实需要多行代码,但它仍然相当短,并且确实删除了单个和多个 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
Note that if you don't need the
preserve
argument then the line initializingk
can be omitted and theif
simplified to:if (x[[1]] == as.name("offset")) return(x[[1]])
2) terms 这既不直接使用字符串操作也不使用递归。首先获取 terms
对象,删除它的 offset
属性并使用我们从 terms.formula
中提取的 fixFormulaObject
修复它。通过将 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
Note that if you don't need the
preserve
argument then the line that zaps the offset attribute can be simplified to:attr(tt, "offset") <- NULL