我试图创建一个更简洁的版本这个解决方案,其中涉及指定公式的右侧,形式为d1 + d1:d2
。
鉴于在公式上下文中*
是完整交互的简洁代替(即d1 * d2
给出d1 + d2 + d1:d2
),我的方法是尝试定义另一种运算符,例如使用中缀方法,如我在其他应用程序中所习惯的那样,a la: %+:%
。
"%+:%" <- function(d1,d2) d1 + d2 + d1:d2
然而,这种可预测的失败是因为我对评估没有仔细处理;让我们举一个例子来说明我的进展:
set.seed(1029)
v1 <- runif(1000)
v2 <- runif(1000)
y <- .8*(v1 < .3) + .2 * (v2 > .25 & v2 < .8) -
.4 * (v2 > .8) + .1 * (v1 > .3 & v2 > .8)
希望这个例子可以清楚地说明,为什么简单地写出这两个术语可能是不可取的。y ~ cut(v2, breaks = c(0, .25, .8, 1)) +
cut(v2, breaks = c(0, .25, .8, 1)):I(v1 < .3)
一个接近我所期望的输出的解决方案是将整个公式定义为函数:
plus.times <- function(outvar, d1, d2){
as.formula(paste0(quote(outvar), "~", quote(d1),
"+", quote(d1), ":", quote(d2)))
}
当传递给lm
时,这会给出预期的系数,但是名称更难以直接解释(特别是在真实数据中,我们会注意为d1
和d2
提供描述性名称,与这个通用示例相反):
out1 <- lm(y ~ cut(v2, breaks = c(0, .25, .8, 1)) +
cut(v2, breaks = c(0, .25, .8, 1)):I(v1 < .3))
out2 <- lm(plus.times(y, cut(v2, breaks = c(0, .25, .8, 1)), I(v1 < .3)))
any(out1$coefficients != out2$coefficients)
# [1] FALSE
names(out2$coefficients)
# [1] "(Intercept)" "d1(0.25,0.8]" "d1(0.8,1]" "d1(0,0.25]:d2TRUE"
# [5] "d1(0.25,0.8]:d2TRUE" "d1(0.8,1]:d2TRUE"
所以这不是最理想的。
有没有办法定义调整代码,使我提到的中缀运算符按预期工作?修改plus.times
的形式,使变量不被重命名如何?
我一直在尝试探索(?formula
, ?"~"
, ?":"
, getAnywhere(formula.default)
, 这个回答等),但还没有看到R在公式中遇到*
时如何解释它,以便我可以进行所需的微调。
formula
可以理解的每个符号,但是他们似乎只使用了tildeSymbol
。这是否意味着我不能得到自己的中缀表达式而不降至 C 并定义类似于此处所做的plusColonSymbol
? - MichaelChiricomodel.frame()
结果的terms
组件,然后(2)查看这里的代码... - Ben Bolker