Como especificar contrastes específicos para ANOVA de medidas repetidas usando carro?

12

Estou tentando executar uma Anova de medidas repetidas em R, seguida de alguns contrastes específicos nesse conjunto de dados. Eu acho que a abordagem correta seria usar Anova()o pacote do carro.

Vamos ilustrar minha pergunta com o exemplo retirado do ?Anovauso dos OBrienKaiserdados (Nota: omiti o fator sexo do exemplo):
Temos um design com um fator entre sujeitos, tratamento (3 níveis: controle, A, B) e 2 repetidos fatores de medidas (dentro dos sujeitos), fase (3 níveis: pré-teste, pós-teste, acompanhamento) e hora (5 níveis: 1 a 5).

A tabela ANOVA padrão é dada por (ao contrário do exemplo (Anova), mudei para Soma de quadrados do tipo 3, que é o que meu campo deseja):

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)

Agora, imagine que a interação de mais alta ordem teria sido significativa (o que não é o caso) e gostaríamos de explorá-la ainda mais com os seguintes contrastes:
Existe uma diferença entre as horas 1 e 2 versus as horas 3 (contraste 1) e entre as horas 1 e 2 versus horas 4 e 5 (contraste 2) nas condições de tratamento (A&B juntas)?
Em outras palavras, como faço para especificar esses contrastes:

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

Minha idéia seria executar outra ANOVA, omitindo a condição de tratamento não necessária (controle):

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)

No entanto, ainda não tenho idéia de como configurar a matriz de contraste dentro do sujeito apropriada comparando as horas 1 e 2 com 3 e 1 e 2 com 4 e 5. E não tenho certeza se a omissão do grupo de tratamento não necessário é realmente uma boa ideia, pois altera o termo geral do erro.

Antes de ir, Anova()eu também estava pensando em ir lme. No entanto, existem pequenas diferenças nos valores de F ep entre a ANOVA do livro e o que é retornado anove(lme) devido a possíveis variações negativas na ANOVA padrão (que não são permitidaslme ). Da mesma forma, alguém me indicou o glsque permite o ajuste de medidas repetidas ANOVA, no entanto, não há argumento de contraste.

Para esclarecer: eu quero um teste F ou t (usando somas de quadrados do tipo III) que responda se os contrastes desejados são significativos ou não.


Atualizar:

Eu já fiz uma pergunta muito semelhante no R-help, não houve resposta .

Perguntas semelhantes foram feitas no R-help há algum tempo. No entanto, as respostas também não resolveram o problema.


Atualização (2015):

Como essa pergunta ainda gera alguma atividade, especificar teses e basicamente todos os outros contrastes agora pode ser feito de maneira relativamente fácil com o afexpacote em combinação com o lsmeanspacote, conforme descrito na vinheta afex .

Henrik
fonte
1
Você já decidiu não usar testes t? O que eu quero dizer é 1) jogar fora os dados do grupo de controle, 2) ignorar os diferentes níveis de treatment, 3) para cada pessoa média acima dos níveis de prePostFup, 4) para cada pessoa média durante horas 1,2 (= grupo de dados 1) bem como durante as horas 3,4 (= grupo de dados 2), 5) execute o teste t para 2 grupos dependentes. Como Maxwell e Delaney (2004), bem como Kirk (1995), desencorajam contrastes com um termo de erro comum em projetos internos, essa poderia ser uma alternativa simples.
29511 caracal
Eu gostaria de fazer análises de contraste e não testes t agrupados. A razão é que os contrastes (apesar de seus problemas) parecem ser o procedimento padrão em Psicologia e são o que os leitores / revisores / supervisores desejam. Além disso, eles são relativamente simples de fazer no SPSS. No entanto, apesar dos meus 2 anos como usuário ativo de R até agora, não consegui alcançá-lo com R. Agora tenho que fazer alguns contrastes e não quero voltar ao SPSS apenas para isso. Quando R é o futuro (o que eu acho que é), os contrastes devem ser possíveis.
Henrik

Respostas:

6

Esse método geralmente é considerado "antiquado", portanto, embora seja possível, a sintaxe é difícil e suspeito que menos pessoas saibam como manipular os comandos anova para obter o que deseja. O método mais comum é usar glhtcom um modelo baseado em probabilidade de nlmeou lme4. (Eu certamente sou bem-vindo ao provar que estou errado com outras respostas.)

Dito isto, se eu precisasse fazer isso, não me incomodaria com os comandos anova; Eu apenas ajustaria o modelo equivalente usando lm, escolheria o termo de erro correto para esse contraste e calcularia o teste F (ou equivalente, teste t, pois há apenas 1 df). Isso exige que tudo seja equilibrado e tenha esfericidade, mas, se você não tiver, provavelmente deverá usar um modelo baseado em probabilidade de qualquer maneira. Você pode corrigir um pouco a não-esfericidade usando as correções de Greenhouse-Geiser ou Huynh-Feldt que (acredito) usam a mesma estatística F, mas modificam o df do termo de erro.

Se você realmente deseja usar car, poderá achar úteis as vinhetas de heplot ; eles descrevem como as matrizes no carpacote são definidas.

Usando o método de caracal (para os contrastes 1 e 2 - 3 e 1 e 2 - 4 e 5), recebo

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

É assim que eu obteria os mesmos valores p:

Remodele os dados em formato longo e execute lmpara obter todos os termos do 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)

Faça uma matriz de contraste alternativa para o período da hora.

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

Verifique se meus contrastes dão o mesmo SS que os contrastes padrão (e os mesmos do modelo completo).

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

Obtenha o SS e o df apenas para os dois contrastes que eu quero.

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

Obtenha os valores-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

Opcionalmente, ajuste a esfericidade.

pf(F, 1*.48867, 52*.48867, lower=FALSE)
pf(F, 1*.57413, 52*.57413, lower=FALSE)
Aaron deixou Stack Overflow
fonte
Isso também funciona! E obrigado pelo link para a heplotsvinheta, esse é realmente um bom resumo do que está acontecendo em termos do modelo linear geral.
Caracal
Muito obrigado. Aceitarei esta resposta (em vez da outra grande resposta), pois inclui algumas reflexões sobre a correção da esfericidade.
Henrik
Nota para futuros leitores: a correção de esfericidade é igualmente aplicável à outra solução.
Aaron saiu de Stack Overflow
6

Se você quiser / precisar usar contrastes com o termo de erro agrupado da ANOVA correspondente, faça o seguinte. Infelizmente, isso será longo e não sei como fazer isso de maneira mais conveniente. Ainda assim, acho que os resultados estão corretos, pois são verificados contra Maxwell & Delaney (veja abaixo).

Você deseja comparar grupos do seu primeiro fator hourdentro de um projeto SPF-p.qr (notação de Kirk (1995): Projeto fatorial de plotagem dividida 1 entre fator treatmentcom grupos p, primeiro dentro do fator hourcom grupos q, segundo dentro do fator prePostFupcom grupos). A seguir, assume-se treatmentgrupos de tamanho idêntico e esfericidade.

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

Primeiro, observe que o efeito principal de houré o mesmo após a média da média prePostFup, passando para o design mais simples do SPF-pq que contém apenas treatmente hourcomo IVs.

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

Agora observe que no SPF-pq ANOVA, o efeito de houré testado contra a interação id:hour, ou seja, essa interação fornece o termo de erro para o teste. Agora, os contrastes para hourgrupos podem ser testados como em uma ANOVA de via única entre os sujeitos, simplesmente substituindo o termo de erro e os graus de liberdade correspondentes. A maneira mais fácil de obter o SS e o df dessa interação é ajustar o modelo 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

Mas também vamos calcular tudo manualmente aqui.

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

caracal
fonte
Boa resposta. Isso é mais ou menos o que eu teria feito se tivesse paciência para resolver tudo.
Aaron saiu de Stack Overflow
Obrigado pela sua resposta detalhada. Embora pareça um pouco impraticável na prática.
Henrik