2012-10-19 31 views
50

其他人的功能似乎採取公式對象,然後對他們內心深處的黑暗魔法,我很嫉妒。有沒有更好的替代字符串操作來編程建立公式?

我在寫一個適合多個模型的函數。這些模型的部分公式保持不變,並且從一個模型到另一個模型的部分變化。笨拙的方法是讓用戶輸入公式部分作爲字符串,對它們進行一些字符操作,然後使用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 

或...

​​

...但遺憾的是沒有語法的作品。有人知道是否有這樣的事情嗎?謝謝。

+0

即使我最終意識到我不需要相當的普遍性水平,而是更好地使用'update'函數,mnel的答案是一個很好的和有用的答案,並且可能已經完成了我原本是在嘗試。但總的來說,我贊成很好的答案,但不接受他們,直到我真正嘗試並能爲他們擔保。在很多情況下,我自己找到了更好的答案,並且當我有時間時應該提交自我回答。我接受答案的標準太嚴格了嗎? – f1r3br4nd

回答

62

reformulate會做你想做的。

reformulate(termlabels = c('x','z'), response = 'y') 
## y ~ x + z 

或沒有攔截

reformulate(termlabels = c('x','z'), response = 'y', intercept = FALSE) 
## y ~ x + z - 1 

請注意,你不能構建公式多reponsesx+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 
+9

+1爲您的偉大摘要。但讓我們承認這一點:它只是表明,如果您想要輕鬆閱讀代碼,那麼通過字符串使用這種方法是最好的選擇。我懷疑,總結一生,速度的增加會讓你有時間喝杯咖啡。 –

+16

@DieterMenne速度的增加並不重要 - 安全性的提高非常重要。第一次有人試圖用非語法變量名稱(即「a b」)使用你的代碼時,它會打破一個奇怪的錯誤,這將需要你幾個小時找到。 – hadley

+0

有沒有其他方法可以使用'.'而不是'update.formula'?我最終使用了'setdiff()'語句,我希望在'reconfulate()'中使用'〜。-var1-var2',並且幫助沒有提及該用例。 –

相關問題