2013-06-30 15 views
7

Sto cercando di scorrere un lungo vettore di potenziali variabili esplicative, regredendo una variabile di risposta su ciascuna a turno. Invece di incollare insieme la formula del modello , sto pensando di utilizzare reformulate(), as demonstrated here.Eventuali insidie ​​nell'utilizzo di formule progettate in modo programmatico?

La funzione fun() sembra eseguire il lavoro, adattando il modello desiderato. Si noti, tuttavia, che registra nel proprio elemento di chiamata il nome dell'oggetto formula costruito anziché il valore .

## (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 

La mia domanda: C'è qualche pericolo in questo? Questo può diventare un problema se, ad esempio, voglio applicare in seguito update o predict o qualche altra funzione all'oggetto di adattamento del modello, (probabilmente da qualche altro ambiente)?

Un'alternativa leggermente più scomoda che fa, tuttavia, ottenere il diritto di chiamata registrato è utilizzare eval(substitute()). Questo è in qualche modo un costrutto generalmente più sicuro?

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

Penso che il problema sarà accurato usando 'update' vedere [http://stackoverflow.com/questions/13690184/update-inside-a-function-only-searches-the-global-environment]. Di solito puoi scoprire queste trappole provando ad usare 'data.table' - vedi [http://stackoverflow.com/questions/15096811/why-is-using-update-on-a-lm-inside-a- grouped-data-table-lose-its-model-data/15376891 # 15376891] – mnel

+3

Funziona: 'do.call (" lm ", lista (ff, quote (mtcars)))' –

+0

@ G.Grothendieck - Grazie . Sembra buono, e sembra che non dovrebbe creare problemi lungo la strada. (Inoltre, grazie mnel per i collegamenti interessanti.) –

risposta

2

sono sempre riluttanti a rivendicare ci sono non situazioni in cui qualcosa che coinvolgono ambienti R e scoping potrebbe mordere, ma ... dopo un po 'di esplorazione, il mio primo utilizzo di sopra ha l'aspetto di sicurezza.

Si scopre che la chiamata stampata è un po 'di falsa pista.

La formula che effettivamente si abitua da altre funzioni (e quella estratta da formula() e as.formula()) è quello memorizzato nell'elemento terms dell'oggetto in forma, e esso ottiene la giusta formula attuale. (L'elemento terms contiene un oggetto della classe "terms", che è solo un "formula" con un gruppo di attributi allegati.)

di vedere che tutte le proposte in mia domanda ei commenti associati memorizzare lo stesso "formula" oggetto (fino a l'ambiente associato), eseguire quanto segue.

## 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 

Per confermare che formula() realmente fa derivare la sua uscita dall'elemento terms dell'oggetto in forma, dare un'occhiata a stats:::formula.lm e stats:::formula.terms.

+0

Bella esplorazione. Ho usato il metodo 'do.call' in precedenza a causa di alcune di queste stesse domande. È bello sapere che queste funzioni non dipendono dalla formula/chiamata memorizzata. Tuttavia, credo che l'aggiornamento sia, quindi fai attenzione a quell'uso. – Aaron

+0

@ Aaron - Grazie. Ti riferisci allo stesso problema che ha fatto mnel nel primo commento che segue la mia domanda? In tal caso, ho ragione nel capire che quel trabocchetto si applicherebbe ugualmente a * qualsiasi * delle chiamate di cui sopra? (es. l'uso di 'do.call()' per lanciare la chiamata a 'lm()' non aiuta a evitare problemi di scoping di 'update()', giusto?) –

+1

Dopo ulteriori esplorazioni, sembra che 'update' sia sicuro anche Ero sicuro che non lo fosse, ma forse ho sbagliato tutto questo tempo. Tuttavia, ci sono funzioni che dipendono dal fatto che la funzione sia corretta, ad esempio 'anova.lme'; vedi http://stackoverflow.com/q/7666807/210673. – Aaron

Problemi correlati