2013-06-30 5 views
7

Ich möchte durch einen langen Vektor von möglichen erklärenden Variablen, eine Regressionsvariable auf jeder der Reihe nach durchlaufen. Anstatt die Modellformel zusammenzufügen, denke ich an reformulate(), as demonstrated here.Irgendwelche Fallstricke bei der Verwendung von programmatisch konstruierten Formeln?

Die unten angegebene Funktion fun() scheint die Aufgabe zu erfüllen und passt das gewünschte Modell an. Beachten Sie jedoch, dass in seinem Aufrufelement die Name der konstruierten Formel Objekt eher als Wert notiert.

## (1) Function using programatically contructed formula 
fun <- function(XX) { 
    ff <- reformulate(response="mpg", termlabels=XX) 
    lm(ff, data=mtcars) 
} 
fun(XX=c("cyl", "disp")) 
# 
# Call: 
# lm(formula = ff, data = mtcars)     <<<--- Note recorded call 
# 
# Coefficients: 
# (Intercept)   cyl   disp 
# 34.66099  -1.58728  -0.02058 

## (2) Result of directly specified formula (just for purposes of comparison) 
lm(mpg ~ cyl + disp, data=mtcars) 
# 
# Call: 
# lm(formula = mpg ~ cyl + disp, data = mtcars) <<<--- Note recorded call 
# 
# Coefficients: 
# (Intercept)   cyl   disp 
# 34.66099  -1.58728  -0.02058 

Meine Frage: Besteht die Gefahr, in diesem? Kann dies ein Problem werden, wenn ich zum Beispiel später eine andere Funktion auf das Modellanpassungsobjekt anwenden möchte (möglicherweise aus einer anderen Umgebung)? update oder predict oder ?

Eine etwas peinlichere Alternative, die jedoch die aufgezeichnete Call-Recht erhalten, ist eval(substitute()) zu verwenden. Ist das in irgendeiner Weise ein allgemein sichereres Konstrukt?

fun2 <- function(XX) { 
    ff <- reformulate(response="mpg", termlabels=XX) 
    eval(substitute(lm(FF, data=mtcars), list(FF=ff))) 
} 
fun2(XX=c("cyl", "disp"))$call 
## lm(formula = mpg ~ cyl + disp, data = mtcars) 
+2

Ich denke, das Problem wird vorsichtig mit 'update' siehe [http://stackoverflow.com/questions/13690184/update-inside-a-function-only-searches-the-global-environment]. Sie können diese Fallstricke normalerweise herausfinden, indem Sie versuchen, 'data.table' zu ​​verwenden - siehe [http://stackoverflow.com/questions/15096811/why-is-using-update-on-a-lm-inside-a- grouped-data-table-loss-it-model-data/15376891 # 15376891] – mnel

+3

Das funktioniert: 'do.call (" lm ", Liste (ff, Zitat (mtcars)))' –

+0

@ G.Grothiedieck - Danke . Das sieht gut aus und scheint auf der Straße keine Probleme zu bereiten. (Danke auch mnel für die interessanten Links.) –

Antwort

2

Ich bin immer zögerlich, dort zu behaupten, sind keine Situationen, in denen etwas Einbeziehung R Umgebungen und Scoping könnte beißen, aber ... nach etwas mehr Exploration, meine erste Nutzung über sichere sieht.

Es stellt sich heraus, dass der gedruckte Anruf ein bisschen Hering ist.

Die Formel, die tatsächlich durch andere Funktionen (und die von formula() und as.formula() extrahiert) ist derjenige, gespeichert in dem terms Elemente des fit-Objekts, und es erhält die eigentliche Formel rechts gewöhnt. (Das terms Element enthält ein Objekt der Klasse "terms", das nur ein "formula" mit einem Bündel angebracht Attribute.)

Um zu sehen, dass alle Vorschläge in meiner Frage und die damit verbundenen Kommentare speichern das gleiche "formula" Objekt (bis zu die zugehörige Umgebung), führen Sie Folgendes aus.

## First the three approaches in my post 
formula(fun(XX=c("cyl", "disp"))) 
# mpg ~ cyl + disp 
# <environment: 0x026d2b7c> 

formula(lm(mpg ~ cyl + disp, data=mtcars)) 
# mpg ~ cyl + disp 

formula(fun2(XX=c("cyl", "disp"))$call) 
# mpg ~ cyl + disp 
# <environment: 0x02c4ce2c> 

## Then Gabor Grothendieck's idea 
XX = c("cyl", "disp") 
ff <- reformulate(response="mpg", termlabels=XX) 
formula(do.call("lm", list(ff, quote(mtcars)))) 
## mpg ~ cyl + disp 

Um zu bestätigen, dass formula() wirklich seinen Ausgang von dem terms Element des Sitzes Objekt abzuleiten, haben einen Blick auf stats:::formula.lm und stats:::formula.terms.

+0

Schöne Erkundung. Ich habe die 'do.call'-Methode zuvor wegen einiger dieser Fragen verwendet. Es ist schön zu wissen, dass diese Funktionen nicht von der gespeicherten Formel/dem gespeicherten Anruf abhängen. Ich glaube jedoch, dass 'update' das tut, also pass auf diese Verwendung auf. – Aaron

+0

@Aaron - Danke. Beziehen Sie sich auf das gleiche Problem wie mnel im ersten Kommentar nach meiner Frage? Wenn dem so ist, habe ich recht zu verstehen, dass diese Fallstricke gleichermaßen für alle obigen Anrufe gelten würde? (Das heißt, 'do.call()' zu verwenden, um den Aufruf von 'lm()' zu starten, hilft Ihnen '' update()''s Scoping-Probleme nicht zu vermeiden, richtig?) –

+1

Nach einer weiteren Erkundung sieht es aus wie 'update' sicher auch. Ich war mir sicher, dass es das nicht war, aber vielleicht lag ich die ganze Zeit falsch. Es gibt jedoch Funktionen, die davon abhängen, dass die Funktion korrekt ist, z. B. "anova.lme"; siehe http://stackoverflow.com/q/7666807/210673. – Aaron

Verwandte Themen