Ответ 1
1) Рекурсия Рекурсивно спуститесь через формулу, заменив offset(...)
на offset
, а затем удалите offset
с помощью update
. Никакой манипуляции с строкой не выполняется, и хотя для этого требуется несколько строк кода, он все еще довольно короткий и удаляет одиночные и множественные термины offset
.
Если есть несколько смещений, можно сохранить некоторые из них, установив preserve
так, например, если preserve = 2
, то второе смещение сохраняется и любые другие удаляются. Значение по умолчанию - сохранить его, т.е. Удалить все.
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 атрибут offset может быть упрощен до:attr(tt, "offset") <- NULL