Come specificare contrasti specifici per misure ripetute ANOVA usando l'auto?


12

Sto cercando di eseguire misure ripetute Anova in R seguito da alcuni contrasti specifici su quel set di dati. Penso che l'approccio corretto sarebbe quello di utilizzare Anova()dal pacchetto auto.

Permettiamo di illustrare la mia domanda con l'esempio tratto ?Anovadall'uso dei OBrienKaiserdati (Nota: ho scelto il fattore di genere dall'esempio):
abbiamo un progetto con uno tra soggetti fattore, trattamento (3 livelli: controllo, A, B) e 2 ripetuti -misura (all'interno dei soggetti) fattori, fase (3 livelli: pretest, posttest, followup) e ora (5 livelli: da 1 a 5).

La tabella standard ANOVA è data da (a differenza dell'esempio (Anova) sono passato a Somma di quadrati di tipo 3, questo è ciò che il mio campo vuole):

require(car)
phase <- factor(rep(c("pretest", "posttest", "followup"), c(5, 5, 5)),
levels=c("pretest", "posttest", "followup"))
hour <- ordered(rep(1:5, 3))
idata <- data.frame(phase, hour)
mod.ok <- lm(cbind(pre.1, pre.2, pre.3, pre.4, pre.5, post.1, post.2, post.3, post.4, post.5, fup.1, fup.2, fup.3, fup.4, fup.5) ~ treatment, data=OBrienKaiser)
av.ok <- Anova(mod.ok, idata=idata, idesign=~phase*hour, type = 3)
summary(av.ok, multivariate=FALSE)

Ora, immagina che l'interazione di ordine più elevato sarebbe stata significativa (il che non è il caso) e vorremmo esplorarla ulteriormente con i seguenti contrasti:
C'è una differenza tra le ore 1 e 2 rispetto alle ore 3 (contrasto 1) e tra le ore 1 e 2 rispetto alle ore 4 e 5 (contrasto 2) nelle condizioni di trattamento (A&B insieme)?
In altre parole, come posso specificare questi contrasti:

  1. ((treatment %in% c("A", "B")) & (hour %in% 1:2)) contro ((treatment %in% c("A", "B")) & (hour %in% 3))
  2. ((treatment %in% c("A", "B")) & (hour %in% 1:2)) contro ((treatment %in% c("A", "B")) & (hour %in% 4:5))

La mia idea sarebbe quella di eseguire un altro ANOVA che offra la condizione di trattamento non necessaria (controllo):

mod2 <- lm(cbind(pre.1, pre.2, pre.3, pre.4, pre.5, post.1, post.2, post.3, post.4, post.5, fup.1, fup.2, fup.3, fup.4, fup.5) ~ treatment, data=OBrienKaiser, subset = treatment != "control")
av2 <- Anova(mod2, idata=idata, idesign=~phase*hour, type = 3)
summary(av2, multivariate=FALSE)

Tuttavia, non ho ancora idea di come impostare la matrice di contrasto all'interno del soggetto appropriata confrontando le ore 1 e 2 con 3 e 1 e 2 con 4 e 5. E non sono sicuro se omettere il gruppo di trattamento non necessario sia davvero una buona idea in quanto cambia il termine generale di errore.

Prima di andare, Anova()stavo anche pensando di farlo lme. Tuttavia, ci sono piccole differenze nei valori F e p tra il manuale ANOVA e ciò che viene restituito a anove(lme) causa di possibili variazioni negative nell'ANOVA standard (che non sono consentite inlme ). Allo stesso modo, qualcuno mi ha indicato glsche consente di adattare misure ripetute ANOVA, tuttavia, non ha argomenti di contrasto.

Per chiarire: voglio un test F o t (usando somme di quadrati di tipo III) che risponda se i contrasti desiderati sono significativi o meno.


Aggiornare:

Ho già fatto una domanda molto simile su R-help, non ho avuto risposta .

Una domanda simile è stata posta su R-help qualche tempo fa. Tuttavia, anche le risposte non hanno risolto il problema.


Aggiornamento (2015):

Dato che questa domanda genera ancora qualche attività, specificare le tesi e praticamente tutti gli altri contrasti ora può essere fatto relativamente facilmente con il afexpacchetto in combinazione con il lsmeanspacchetto come descritto nella vignetta afex .


1
Hai già deciso di non utilizzare i test t? Ciò che intendo è 1) eliminare i dati dal gruppo di controllo, 2) ignorare i diversi livelli di treatment, 3) per ogni persona media su livelli di prePostFup, 4) per ogni persona media su ore 1,2 (= gruppo di dati 1) oltre alle ore 3,4 (= gruppo di dati 2), 5) eseguire il test t per 2 gruppi dipendenti. Dal momento che Maxwell & Delaney (2004) e Kirk (1995) scoraggiano i contrasti con un termine di errore aggregato nei progetti interni, questa potrebbe essere una semplice alternativa.
Caracal,

Vorrei fare analisi di contrasto e non test t pool. La ragione è che i contrasti (nonostante i loro problemi) sembrano essere la procedura standard in Psicologia e sono ciò che vogliono i lettori / revisori / supervisori. Inoltre, sono relativamente semplici da eseguire in SPSS. Tuttavia, nonostante i miei 2 anni come utente R attivo finora non sono stato in grado di raggiungerlo con R. Ora devo fare alcuni contrasti e non voglio tornare a SPSS solo per questo. Quando R è il futuro (che penso sia), i contrasti devono essere possibili.
Henrik,

Risposte:


6

Questo metodo è generalmente considerato "vecchio stile", quindi sebbene sia possibile, la sintassi è difficile e sospetto che meno persone sappiano come manipolare i comandi anova per ottenere ciò che desideri. Il metodo più comune sta usando glhtun modello basato sulla verosimiglianza da nlmeo lme4. (Sono certamente benvenuto per essere smentito da altre risposte però.)

Detto questo, se avessi bisogno di farlo, non mi preoccuperei dei comandi anova; Mi limiterei ad adattare il modello equivalente usando lm, sceglierei il giusto termine di errore per questo contrasto e calcolare da solo il test F (o equivalentemente, test t poiché c'è solo 1 df). Ciò richiede che tutto sia bilanciato e abbia sfericità, ma se non lo hai, probabilmente dovresti comunque utilizzare un modello basato sulla verosimiglianza. Potresti essere in grado di correggere in qualche modo la non sfericità usando le correzioni Greenhouse-Geiser o Huynh-Feldt che (credo) usano la stessa statistica F ma modificano la df del termine di errore.

Se vuoi davvero usarlo car, potresti trovare utili le vignette heplot ; descrivono come carsono definite le matrici nel pacchetto.

Usando il metodo di Caracal (per i contrasti 1 e 2 - 3 e 1 e 2 - 4 e 5), ottengo

      psiHat      tStat          F         pVal
1 -3.0208333 -7.2204644 52.1351067 2.202677e-09
2 -0.2083333 -0.6098777  0.3719508 5.445988e-01

Ecco come ottenere quegli stessi valori p:

Rimodella i dati in un formato lungo ed esegui lmper ottenere tutti i termini SS.

library(reshape2)
d <- OBrienKaiser
d$id <- factor(1:nrow(d))
dd <- melt(d, id.vars=c(18,1:2), measure.vars=3:17)
dd$hour <- factor(as.numeric(gsub("[a-z.]*","",dd$variable)))
dd$phase <- factor(gsub("[0-9.]*","", dd$variable), 
                   levels=c("pre","post","fup"))
m <- lm(value ~ treatment*hour*phase + treatment*hour*phase*id, data=dd)
anova(m)

Crea una matrice di contrasto alternativa per il termine orario.

foo <- matrix(0, nrow=nrow(dd), ncol=4)
foo[dd$hour %in% c(1,2) ,1] <- 0.5
foo[dd$hour %in% c(3) ,1] <- -1
foo[dd$hour %in% c(1,2) ,2] <- 0.5
foo[dd$hour %in% c(4,5) ,2] <- -0.5
foo[dd$hour %in% 1 ,3] <- 1
foo[dd$hour %in% 2 ,3] <- 0
foo[dd$hour %in% 4 ,4] <- 1
foo[dd$hour %in% 5 ,4] <- 0

Verifica che i miei contrasti forniscano gli stessi SS dei contrasti predefiniti (e gli stessi del modello completo).

anova(lm(value ~ hour, data=dd))
anova(lm(value ~ foo, data=dd))

Ottieni SS e df solo per i due contrasti che voglio.

anova(lm(value ~ foo[,1], data=dd))
anova(lm(value ~ foo[,2], data=dd))

Ottieni i valori p.

> F <- 73.003/(72.81/52)
> pf(F, 1, 52, lower=FALSE)
[1] 2.201148e-09
> F <- .5208/(72.81/52)
> pf(F, 1, 52, lower=FALSE)
[1] 0.5445999

Opzionalmente regolare per la sfericità.

pf(F, 1*.48867, 52*.48867, lower=FALSE)
pf(F, 1*.57413, 52*.57413, lower=FALSE)

Funziona anche! E grazie per il link alla heplotsvignetta, questo è davvero un bel riassunto di ciò che sta accadendo in termini di modello lineare generale.
Caracal,

Molte grazie. Accetterò questa risposta (invece dell'altra grande risposta), poiché include alcune riflessioni sulla correzione della sfericità.
Henrik,

Nota per i futuri lettori: la correzione della sfericità è ugualmente applicabile anche all'altra soluzione.
Aaron ha lasciato Stack Overflow il

6

Se si desidera / è necessario utilizzare i contrasti con il termine di errore aggregato dall'ANOVA corrispondente, è possibile effettuare le seguenti operazioni. Sfortunatamente, questo sarà lungo e non so come farlo più comodamente. Tuttavia, penso che i risultati siano corretti, in quanto verificati contro Maxwell e Delaney (vedi sotto).

Volete confrontare i gruppi del vostro primo fattore all'interno hourdi un disegno SPF-p.qr (notazione da Kirk (1995): disegno diviso-grafico -fattoriale 1 tra fattore treatmentcon gruppi p, prima all'interno di fattore hourcon gruppi q, secondo entro fattore prePostFupcon gruppi r). Quanto segue assume treatmentgruppi di dimensioni identiche e sfericità.

Nj    <- 10                                             # number of subjects per group
P     <- 3                                              # number of treatment groups
Q     <- 5                                              # number of hour groups
R     <- 3                                              # number of PrePostFup groups
id    <- factor(rep(1:(P*Nj), times=Q*R))                                  # subject
treat <- factor(rep(LETTERS[1:P], times=Q*R*Nj), labels=c("CG", "A", "B")) # treatment
hour  <- factor(rep(rep(1:Q, each=P*Nj), times=R))                         # hour
ppf   <- factor(rep(1:R, each=P*Q*Nj), labels=c("pre", "post", "fup"))     # prePostFup
DV    <- round(rnorm(Nj*P*Q*R, 15, 2), 2)               # some data with no effects
dfPQR <- data.frame(id, treat, hour, ppf, DV)           # data frame long format

summary(aov(DV ~ treat*hour*ppf + Error(id/(hour*ppf)), data=dfPQR)) # SPF-p.qr ANOVA

Prima nota che l'effetto principale per hourè lo stesso dopo aver superato la media prePostFup, passando così al design SPF-pq più semplice che contiene solo treatmente hourcome IV.

dfPQ <- aggregate(DV ~ id + treat + hour, FUN=mean, data=dfPQR)  # average over ppf
# SPF-p.q ANOVA, note effect for hour is the same as before
summary(aov(DV ~ treat*hour + Error(id/hour), data=dfPQ))

Si noti ora che nell'ANOVA SPF-pq l'effetto per hourviene testato rispetto all'interazione id:hour, ovvero questa interazione fornisce il termine di errore per il test. Ora i contrasti per i hourgruppi possono essere testati proprio come in un ANOVA tra soggetti a senso unico semplicemente sostituendo il termine di errore e i corrispondenti gradi di libertà. Il modo più semplice per ottenere SS e df di questa interazione è adattarsi al modello lm().

(anRes <- anova(lm(DV ~ treat*hour*id, data=dfPQ)))
SSE    <- anRes["hour:id", "Sum Sq"]     # SS interaction hour:id -> will be error SS
dfSSE  <- anRes["hour:id", "Df"]         # corresponding df

Ma calcoliamo anche tutto manualmente qui.

# substitute DV with its difference to cell / person / treatment group means
Mjk   <- ave(dfPQ$DV,           dfPQ$treat, dfPQ$hour, FUN=mean)  # cell means
Mi    <- ave(dfPQ$DV, dfPQ$id,                         FUN=mean)  # person means
Mj    <- ave(dfPQ$DV,           dfPQ$treat,            FUN=mean)  # treatment means
dfPQ$IDxIV <- dfPQ$DV - Mi - Mjk + Mj                             # interaction hour:id
(SSE  <- sum(dfPQ$IDxIV^2))               # SS interaction hour:id -> will be error SS
dfSSE <- (Nj*P - P) * (Q-1)               # corresponding df
(MSE  <- SSE / dfSSE)                     # mean square

t=ψ^0||c||MSEc||c||ψ^=k=1qckM.kMSEhour:id

Mj     <- tapply(dfPQ$DV, dfPQ$hour, FUN=mean)  # group means for hour
Nj     <- table(dfPQ$hour)                      # cell sizes for hour (here the same)
cntr   <- rbind(c(1, 1, -2,  0, 0),
                c(1, 1, -1, -1, 0))             # matrix of contrast vectors
psiHat <- cntr   %*% Mj                         # estimates psi-hat
lenSq  <- cntr^2 %*% (1/Nj)                     # squared lengths of contrast vectors
tStat  <- psiHat / sqrt(lenSq*MSE)              # t-statistics
pVal   <- 2*(1-pt(abs(tStat), dfSSE))           # p-values
data.frame(psiHat, tStat, pVal)

α

Anova()carϵ^


Bella risposta. Questo è più o meno quello che avrei fatto se avessi avuto la pazienza di risolvere tutto.
Aaron ha lasciato Stack Overflow il

Grazie per la tua risposta dettagliata. Anche se in pratica sembra un po 'invariato.
Henrik,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.