有没有比字符串操作更好的选择来以编程方式构建公式?
Posted
技术标签:
【中文标题】有没有比字符串操作更好的选择来以编程方式构建公式?【英文标题】:Is there a better alternative than string manipulation to programmatically build formulas? 【发布时间】:2012-10-09 16:29:33 【问题描述】:其他人的函数似乎都采用公式对象,然后在内心深处的某个地方对它们施以黑魔法,我很嫉妒。
我正在编写一个适合多个模型的函数。这些模型的部分公式保持不变,而从一个模型到另一个模型的部分变化。笨拙的方法是让用户将公式部分作为字符串输入,对其进行一些字符操作,然后使用as.formula
。
但在我走这条路之前,我只是想确保我没有忽略一些更简洁的方法,它允许函数接受标准 R 格式的公式(例如从其他使用公式的对象中提取)。
我想要...
> LHS <- y~1; RHS <- ~a+b; c(LHS,RHS);
y ~ a + b
> RHS2 <- ~c;
> c(LHS, RHS, RHS2);
y ~ a + b + c
或者...
> LHS + RHS;
y ~ a + b
> LHS + RHS + RHS2;
y ~ a + b + c
...但不幸的是,这两种语法都不起作用。有人知道是否有什么可以做的吗?谢谢。
【问题讨论】:
尽管我最终意识到我并不需要那种通用性,而是更好地利用了update
函数,但下面的 mnel 的答案是一个很好且有用的答案,并且可能有做了我最初尝试的事情。不过,总的来说,我赞成好的答案,但在我真正尝试它们并能保证它们之前不接受它们。在许多情况下,我自己找到了更好的答案,我真的应该在有时间的时候提交自己的答案。我接受答案的标准是否过于严格?
【参考方案1】:
reformulate
会做你想做的事。
reformulate(termlabels = c('x','z'), response = 'y')
## y ~ x + z
或者没有拦截
reformulate(termlabels = c('x','z'), response = 'y', intercept = FALSE)
## y ~ x + z - 1
请注意,您不能构造包含多个reponses
的公式,例如x+y ~z+b
reformulate(termlabels = c('x','y'), response = c('z','b'))
z ~ x + y
从现有的formula
中提取术语(以您的示例为例)
attr(terms(RHS), 'term.labels')
## [1] "a" "b"
要得到响应稍有不同,一个简单的方法(对于单变量响应)。
as.character(LHS)[2]
## [1] 'y'
combine_formula <- function(LHS, RHS)
.terms <- lapply(RHS, terms)
new_terms <- unique(unlist(lapply(.terms, attr, which = 'term.labels')))
response <- as.character(LHS)[2]
reformulate(new_terms, response)
combine_formula(LHS, list(RHS, RHS2))
## y ~ a + b + c
## <environment: 0x577fb908>
我认为将响应指定为字符向量会更明智,例如
combine_formula2 <- function(response, RHS, intercept = TRUE)
.terms <- lapply(RHS, terms)
new_terms <- unique(unlist(lapply(.terms, attr, which = 'term.labels')))
response <- as.character(LHS)[2]
reformulate(new_terms, response, intercept)
combine_formula2('y', list(RHS, RHS2))
您还可以定义 +
运算符来处理公式(更新为公式对象设置新方法)
`+.formula` <- function(e1,e2)
.terms <- lapply(c(e1,e2), terms)
reformulate(unique(unlist(lapply(.terms, attr, which = 'term.labels'))))
RHS + RHS2
## ~a + b + c
你也可以明智地使用update.formula
.
update(~a+b, y ~ .)
## y~a+b
【讨论】:
+1 为您的精彩总结。但是让我们承认这一点:它只是表明,如果您想要易于阅读的代码,则可以通过字符串使用该方法。我怀疑,在整个生命周期中,速度的提升是否会为你赢得喝咖啡的时间。 @DieterMenne 速度的提升并不重要——安全的提升很重要。当有人第一次尝试将您的代码与非语法变量名(即“a b”)一起使用时,它会因一个奇怪的错误而中断,您需要花费数小时才能找到。 除了update.formula
,还有其他方法可以使用.
吗?我最终使用了setdiff()
语句,我本来希望在reformulate()
中使用~.-var1-var2
,而帮助没有提到那个用例。以上是关于有没有比字符串操作更好的选择来以编程方式构建公式?的主要内容,如果未能解决你的问题,请参考以下文章