2015-06-11 40 views
2

在R中的迴歸公式中有幾個與獲得變量列表相關的帖子 - 基本答案是使用all.vars。例如,當有下標時從公式中提取變量

> all.vars(log(resp) ~ treat + factor(dose)) 
[1] "resp" "treat" "dose" 

這很好,因爲它去除了所有的功能和操作符(以及重複,未顯示)。然而,這是有問題的,當配方中含有$運營商或下標,如在

> form = log(cows$weight) ~ factor(bulls[[3]]) * herd$breed 
> all.vars(form) 
[1] "cows" "weight" "bulls" "herd" "breed" 

這裏,數據幀名稱cowsbulls,和herd被識別爲變量,和實際變量的名稱解耦或丟失。相反,我真正想要的是這樣的結果:

> mystery.fcn(form) 
[1] "cows$weight" "bulls[[3]]" "herd$breed" 

什麼是最優雅的方式來做到這一點?我有一個建議,我會作爲答案張貼,但也許有人有一個更優雅的解決方案,並會贏得更多的選票!

+0

那麼,帶有'$'和'[[''的公式是非常有問題的工作,真的應該避免。你認爲他們有必要的情景是什麼?如果我有'〜x [[y]]'和'y < - 「p」'怎麼辦?這個函數返回什麼? – MrFlick

+0

我同意他們應該避免。但我是一名軟件包開發人員,一些用戶會像我說明的那樣適合模型(儘管通常不是那麼極端)。 – rvl

回答

2

一種方法的作品,雖然有點繁瑣,更換運營商$等與變量名合法字符,把字符串返回到一個公式,適用all.vars,並取消裂傷結果:

All.vars = function(expr, retain = c("\\$", "\\[\\[", "\\]\\]"), ...) { 
    # replace operators with unlikely patterns _Av1_, _Av2_, ... 
    repl = paste("_Av", seq_along(retain), "_", sep = "") 
    for (i in seq_along(retain)) 
     expr = gsub(retain[i], repl[i], expr) 
    # piece things back together in the right order, and call all.vars 
    subs = switch(length(expr), 1, c(1,2), c(2,1,3)) 
    vars = all.vars(as.formula(paste(expr[subs], collapse = "")), ...) 
    # reverse the mangling of names 
    retain = gsub("\\\\", "", retain) # un-escape the patterns 
    for (i in seq_along(retain)) 
     vars = gsub(repl[i], retain[i], vars) 
    vars 
} 

使用retain參數指定我們希望保留的模式,而不是作爲運算符對待。默認值是$[[]](所有正式轉義)下面是一些結果:

> form = log(cows$weight) ~ factor(bulls[[3]]) * herd$breed 
> All.vars(form) 
[1] "cows$weight" "bulls[[3]]" "herd$breed" 

變化retain也包括()

> All.vars(form, retain = c("\\$", "\\(", "\\)", "\\[\\[", "\\]\\]")) 
[1] "log(cows$weight)" "factor(bulls[[3]])" "herd$breed" 

的點傳遞到all.vars,這與all.names確實相同,但具有不同的默認值。因此,我們也能獲得的功能和運營商不retain

> All.vars(form, functions = TRUE) 
[1] "~"   "log"   "cows$weight" "*"   
[5] "factor"  "bulls[[3]]" "herd$breed" 
2

這是不夠的一般使用情況下,但只是爲了好玩,我想我會帶一條縫吧:

mystery.fcn = function(string) { 
    string = gsub(":", " ", string) 
    string = unlist(strsplit(gsub("\\b.*\\b\\(|\\(|\\)|[*~+-]", "", string), split=" ")) 
    string = string[nchar(string) > 0] 
    return(string) 
} 

form = log(cows$weight) ~ factor(bulls[[3]]) * herd$breed 
mystery.fcn(form) 
[1] "cows$weight" "bulls[[3]]" "herd$breed" 

form1 = ~x[[y]] 
mystery.fcn(form1) 
[1] "x[[y]]" 

form2 = z$three ~ z$one + z$two - z$x_y 
mystery.fcn(form2) 
[1] "z$three" "z$one" "z$two" "z$x_y" 

form3 = z$three ~ z$one:z$two 
mystery.fcn(form3) 
[1] "z$three" "z$one" "z$two" 
+0

非常好,但它也需要處理交互操作符':'。我嘗試在括號內的表達式中添加':',但它不適用。 – rvl

+1

我在函數中添加了一個新行來處理這種情況。實際上,處理其他一些情況(例如'x $ y * x $ z')也可能是有意義的。 – eipi10