2015-09-16 20 views
12

Sto provando a creare una versione più parsimoniosa della soluzione this, che comporta l'indicazione dell'RHS di una formula nel formato d1 + d1:d2.Definizione di un operatore infisso per l'uso all'interno di una formula

Dato che * nel contesto di una formula è una concisa stand-in per la piena interazione (cioè d1 * d2d1 + d2 + d1:d2), il mio approccio è stato quello di cercare di definire un operatore alternativo, dire %+:% utilizzando l'approccio infisso ho abituati a in altre applicazioni, alla:

"%+:%" <- function(d1,d2) d1 + d2 + d1:d2 

Tuttavia, questo non riesce prevedibilmente, perché non sono stato attento a valutazione; introduciamo un esempio per illustrare il mio progresso:

set.seed(1029) 
v1 <- runif(1000) 
v2 <- runif(1000) 
y <- .8*(v1 < .3) + .2 * (v2 > .25 & v2 < .8) - 
    .4 * (v2 > .8) + .1 * (v1 > .3 & v2 > .8) 

Con questo esempio, si spera che sia chiaro il motivo per cui semplicemente scrivendo i due termini potrebbe essere indesiderabile:

y ~ cut(v2, breaks = c(0, .25, .8, 1)) + 
    cut(v2, breaks = c(0, .25, .8, 1)):I(v1 < .3) 

Una soluzione che è vicino alla mia uscita desiderata è quello di definire l'intera formula in funzione:

plus.times <- function(outvar, d1, d2){ 
    as.formula(paste0(quote(outvar), "~", quote(d1), 
        "+", quote(d1), ":", quote(d2))) 
} 

Questo dà i coefficienti previsti quando passato a lm, ma con nomi che un re più difficile da interpretare direttamente (soprattutto nei dati reali in cui ci prendiamo cura di dare d1 e d2 nomi descrittivi, in contrasto con questo esempio generico):

out1 <- lm(y ~ cut(v2, breaks = c(0, .25, .8, 1)) + 
      cut(v2, breaks = c(0, .25, .8, 1)):I(v1 < .3)) 
out2 <- lm(plus.times(y, cut(v2, breaks = c(0, .25, .8, 1)), I(v1 < .3))) 
any(out1$coefficients != out2$coefficients) 
# [1] FALSE 
names(out2$coefficients) 
# [1] "(Intercept)"   "d1(0.25,0.8]"  "d1(0.8,1]"   "d1(0,0.25]:d2TRUE" 
# [5] "d1(0.25,0.8]:d2TRUE" "d1(0.8,1]:d2TRUE" 

Quindi questo non è ottimale.

C'è un modo per definire la regolazione del codice in modo che l'operatore di infissi sopra menzionato funzioni come previsto? Che ne dici di alterare la forma di plus.times in modo che le variabili non vengano rinominate?

ho rovistando (?formula, ?"~", ?":", getAnywhere(formula.default), this risposta, ecc), ma non ho visto come esattamente R interpreta * quando è incontrato in una formula in modo che possa fare i miei piccoli aggiustamenti desiderati .

+0

vengono interpretati previsti ::: model.frame.default in c https://github.com/wch/r-source/blob/ed66b715221d2720f5b334470335635bada520b1/src/library/stats/src/model.c#L888 – rawr

+0

@rawr grazie. non posso dire di avere idea di cosa stia succedendo nel codice C - vedo che "definiscono" ciascuno dei simboli compresi da 'formula', ma sembrano usare solo' tildeSymbol'. Questo significa comunque che non sarò in grado di ottenere il mio infisso senza andare a finire in C & definendo, ad esempio 'plusColonSymbol' come si fa qui? – MichaelChirico

+1

@ La risposta di HeatherTurner sembra esattamente giusta per me. Se vuoi davvero iniziare a scherzare con le formule espandibili, ti suggerirei di iniziare (1) guardando il componente 'terms' dei risultati di' model.frame() 'e (2) guardando il codice [qui] (https : //github.com/glmmTMB/glmmTMB/blob/master/glmmTMB/R/utils.R) ... –

risposta

6

In questo caso non è necessario definire un nuovo operatore: in una formula d1/d2 si espande a d1 + d1:d2. In altre parole, d1/d2 specifica che d2 è nidificato entro d1. Continuando il tuo esempio:

out3 <- lm(y ~ cut(v2,breaks=c(0,.25,.8,1))/I(v1 < .3)) 
all.equal(coef(out1), coef(out3)) 
# [1] TRUE 

Ulteriori commenti

fattori possono essere attraversato o nidificato. Due fattori sono incrociati se è possibile osservare ogni combinazione di livelli dei due fattori, ad es. sesso e trattamento, temperatura e pH, ecc. Un fattore è annidato all'interno di un altro se ogni livello di quel fattore può essere osservato solo all'interno di uno dei livelli dell'altro fattore, ad es. città e paese, membro dello staff e negozio ecc.

Queste relazioni si riflettono nella parametrizzazione del modello.Per i fattori incrociati usiamo d1*d2 o d1 + d2 + d1:d2, per dare l'effetto principale di ciascun fattore, più l'interazione. Per i fattori nidificati si utilizza d1/d2 o d1 + d1:d2 per fornire un sottomodello separato del modulo 1 + d2 per ciascun livello di d1.

L'idea di annidamento non è limitata a fattori, ad esempio è possibile utilizzare sex/x per adattarsi a una regressione lineare separata su x per maschi e femmine.

In una formula, %in% equivale a :, ma può essere utilizzato per sottolineare la struttura nidificata o gerarchica del dato/modello. Ad esempio, a + b %in% a è uguale a a + a:b, ma leggerlo come "a più b all'interno di un" fornisce una descrizione migliore del modello che si sta installando. Anche così, l'utilizzo di / ha il vantaggio di semplificare la formula del modello e allo stesso tempo di enfatizzare la struttura.