R 从公式中删除抵销项

R 从公式中删除抵销项,r,formula,R,Formula,R有一个操作公式的便捷工具,update.formula()。当您想要获得类似“包含除x之外的所有前一个公式中的术语的公式”的内容时,此功能非常有效,例如 (即,这似乎不会删除偏移量(b)。) 我知道我可以通过使用deparse()和文本处理,或者通过递归处理公式来删除我不想要的术语,来破解一个解决方案,但这些解决方案很难看,也很烦人。无论是关于为什么这不起作用的启示,还是一个合理紧凑的解决方案,都是非常好的…这似乎是出于设计。但一个简单的解决方法是 offset2 = offset f3 &l

R有一个操作公式的便捷工具,
update.formula()
。当您想要获得类似“包含除
x
之外的所有前一个公式中的术语的公式”的内容时,此功能非常有效,例如

(即,这似乎不会删除偏移量(b)。)


我知道我可以通过使用
deparse()
和文本处理,或者通过递归处理公式来删除我不想要的术语,来破解一个解决方案,但这些解决方案很难看,也很烦人。无论是关于为什么这不起作用的启示,还是一个合理紧凑的解决方案,都是非常好的…

这似乎是出于设计。但一个简单的解决方法是

offset2 = offset
f3 <- z ~ a + offset2(b) 
update(f3, . ~ . - offset2(b))
# z ~ a
1)递归通过公式递归下降,用
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
2)术语这既不直接使用字符串操作,也不使用递归。首先获取
terms
对象,使用我们从
terms.formula
中提取的
fixFormulaObject
对其
offset
属性进行修改。通过将
fixFormulaObject
的源代码复制到源代码中,并删除下面的
eval
行,可以稍微降低脆弱性<代码>保留的作用如(1)所示


术语的代码中再深入一点。公式
表明它明确地保留了偏移术语,尽管这似乎还没有在任何地方被记录……查看
?偏移
,文档中说
“模型公式中可以有多个偏移,但是-不支持偏移术语(相当于+)
。这可能是您的
offset()
术语没有简化的原因吗?这不是最吸引人的,但您是否可以尝试添加
offset(-b)
?您的公式看起来不会简化,但我认为效果应该是一样的。如果您尝试
lm(mpg~cyl,data=mtcars);lm(mpg~cyl+offset(disp),data=mtcars);lm(mpg~cyl+偏移量(disp)+偏移量(-disp),data=mtcars);
您可以看到第一个和第三个
lm()
s是相同的。这对ben来说没什么问题,但是如果用户将公式提供给他的软件包,比如说,那么他们必须事先知道这个警告,对吗?@rawr-是的,如果预期用途是其他用户提供公式的软件包,那么这将是一个问题。然后有必要对公式进行解密并替换任何iBen的软件包中的offset2出现偏移。开始变得丑陋。我不清楚这是否正是OP所寻找的行为。公式中可能有多个偏移项,此方法将删除所有偏移项。我得到的印象是OP只想删除公式中的指定项,如
offset(b)
,这意味着保留
偏移量(c)
。也许@BenBolker可以评论所需的行为?不确定这是否重要,但已将该功能添加到(1)和(2)中。
terms.formula(z ~ a + offset(b) - offset(b), simplify=TRUE)
## z ~ a + offset(b)
offset2 = offset
f3 <- z ~ a + offset2(b) 
update(f3, . ~ . - offset2(b))
# z ~ a
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
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
if (x[[1]] == as.name("offset")) return(x[[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
attr(tt, "offset") <- NULL