Na verdade, não é muito difícil lidar com a heterocedasticidade em modelos lineares simples (por exemplo, modelos ANOVA de uma ou duas vias).
Robustez da ANOVA
Primeiro, como outros observaram, a ANOVA é surpreendentemente robusta a desvios da suposição de variações iguais, especialmente se você tiver dados aproximadamente equilibrados (número igual de observações em cada grupo). Testes preliminares sobre variações iguais, por outro lado, não são (embora o teste de Levene seja muito melhor do que o teste F normalmente ensinado em livros didáticos). Como George Box colocou:
Fazer o teste preliminar de variações é como colocar no mar um barco a remo para descobrir se as condições são suficientemente calmas para um transatlântico sair do porto!
Embora a ANOVA seja muito robusta, como é muito fácil levar em conta a heterocedaticidade, há poucas razões para não fazer isso.
Testes não paramétricos
Se você está realmente interessado em diferenças de médias , os testes não paramétricos (por exemplo, o teste de Kruskal-Wallis) não são realmente úteis. Eles testam diferenças entre grupos, mas geralmente não testam diferenças de médias.
Dados de exemplo
Vamos gerar um exemplo simples de dados em que alguém gostaria de usar ANOVA, mas onde a suposição de variâncias iguais não é verdadeira.
set.seed(1232)
pop = data.frame(group=c("A","B","C"),
mean=c(1,2,5),
sd=c(1,3,4))
d = do.call(rbind, rep(list(pop),13))
d$x = rnorm(nrow(d), d$mean, d$sd)
Temos três grupos, com diferenças (claras) em médias e variações:
stripchart(x ~ group, data=d)
ANOVA
Não é de surpreender que uma ANOVA normal lide com isso muito bem:
> mod.aov = aov(x ~ group, data=d)
> summary(mod.aov)
Df Sum Sq Mean Sq F value Pr(>F)
group 2 199.4 99.69 13.01 5.6e-05 ***
Residuals 36 275.9 7.66
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Então, quais grupos diferem? Vamos usar o método HSD de Tukey:
> TukeyHSD(mod.aov)
Tukey multiple comparisons of means
95% family-wise confidence level
Fit: aov(formula = x ~ group, data = d)
$group
diff lwr upr p adj
B-A 1.736692 -0.9173128 4.390698 0.2589215
C-A 5.422838 2.7688327 8.076843 0.0000447
C-B 3.686146 1.0321403 6.340151 0.0046867
Com um valor P de 0,26, não podemos reivindicar nenhuma diferença (em médias) entre o grupo A e B. E mesmo se não levássemos em conta que fizemos três comparações, não obteríamos um P baixo - valor ( P = 0,12):
> summary.lm(mod.aov)
[…]
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.5098 0.7678 0.664 0.511
groupB 1.7367 1.0858 1.599 0.118
groupC 5.4228 1.0858 4.994 0.0000153 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 2.768 on 36 degrees of freedom
Por que é que? Com base no enredo, não é uma diferença bastante clara. O motivo é que a ANOVA assume variações iguais em cada grupo e estima um desvio padrão comum de 2,77 (mostrado como 'Erro padrão residual' na summary.lm
tabela, ou você pode obtê-lo tomando a raiz quadrada do quadrado médio residual (7,66) na tabela ANOVA).
Mas o grupo A tem um desvio padrão (populacional) de 1, e essa superestimação de 2,77 torna (desnecessariamente) difícil obter resultados estatisticamente significativos, ou seja, temos um teste com (muito) energia baixa.
'ANOVA' com variações desiguais
Então, como ajustar um modelo adequado, que leve em consideração as diferenças nas variações? É fácil no R:
> oneway.test(x ~ group, data=d, var.equal=FALSE)
One-way analysis of means (not assuming equal variances)
data: x and group
F = 12.7127, num df = 2.000, denom df = 19.055, p-value = 0.0003107
Portanto, se você deseja executar uma 'ANOVA' unidirecional simples em R sem assumir variações iguais, use esta função. É basicamente uma extensão do (Welch) t.test()
para duas amostras com variações desiguais.
Infelizmente, ele não funciona com TukeyHSD()
(ou com a maioria das outras funções que você usa em aov
objetos), portanto, mesmo que tenhamos certeza de que existem diferenças entre os grupos, não sabemos onde elas estão.
Modelando a heterocedasticidade
A melhor solução é modelar as variações explicitamente. E é muito fácil no R:
> library(nlme)
> mod.gls = gls(x ~ group, data=d,
weights=varIdent(form= ~ 1 | group))
> anova(mod.gls)
Denom. DF: 36
numDF F-value p-value
(Intercept) 1 16.57316 0.0002
group 2 13.15743 0.0001
Diferenças ainda significativas, é claro. Mas agora as diferenças entre o grupo A e B também se tornaram estatisticamente significativas ( P = 0,025):
> summary(mod.gls)
Generalized least squares fit by REML
Model: x ~ group
[…]
Variance function:
Structure: Different standard
deviations per stratum
Formula: ~1 | group
Parameter estimates:
A B C
1.000000 2.444532 3.913382
Coefficients:
Value Std.Error t-value p-value
(Intercept) 0.509768 0.2816667 1.809829 0.0787
groupB 1.736692 0.7439273 2.334492 0.0253
groupC 5.422838 1.1376880 4.766542 0.0000
[…]
Residual standard error: 1.015564
Degrees of freedom: 39 total; 36 residual
Portanto, usar um modelo apropriado ajuda! Observe também que obtemos estimativas dos desvios padrão (relativos). O desvio padrão estimado para o grupo A pode ser encontrado na parte inferior de, resultados, 1,02. O desvio padrão estimado do grupo B é 2,44 vezes esse valor, ou 2,48, e o desvio padrão estimado do grupo C é similarmente 3,97 (tipo intervals(mod.gls)
para obter intervalos de confiança para os desvios padrão relativos dos grupos B e C).
Corrigindo para vários testes
No entanto, devemos realmente corrigir vários testes. Isso é fácil usando a biblioteca 'multcomp'. Infelizmente, ele não possui suporte interno para objetos 'gls'; portanto, teremos que adicionar algumas funções auxiliares primeiro:
model.matrix.gls <- function(object, ...)
model.matrix(terms(object), data = getData(object), ...)
model.frame.gls <- function(object, ...)
model.frame(formula(object), data = getData(object), ...)
terms.gls <- function(object, ...)
terms(model.frame(object),...)
Agora vamos ao trabalho:
> library(multcomp)
> mod.gls.mc = glht(mod.gls, linfct = mcp(group = "Tukey"))
> summary(mod.gls.mc)
[…]
Linear Hypotheses:
Estimate Std. Error z value Pr(>|z|)
B - A == 0 1.7367 0.7439 2.334 0.0480 *
C - A == 0 5.4228 1.1377 4.767 <0.001 ***
C - B == 0 3.6861 1.2996 2.836 0.0118 *
Ainda diferença estatisticamente significante entre o grupo A e o grupo B! ☺ E podemos obter intervalos de confiança (simultâneos) para as diferenças entre as médias do grupo:
> confint(mod.gls.mc)
[…]
Linear Hypotheses:
Estimate lwr upr
B - A == 0 1.73669 0.01014 3.46324
C - A == 0 5.42284 2.78242 8.06325
C - B == 0 3.68615 0.66984 6.70245
Usando um modelo aproximadamente (aqui exatamente) correto, podemos confiar nesses resultados!
Observe que, para este exemplo simples, os dados do grupo C realmente não adicionam nenhuma informação sobre as diferenças entre o grupo A e B, pois modelamos as médias separadas e os desvios padrão para cada grupo. Poderíamos ter usado apenas testes t pareados, corrigidos para múltiplas comparações:
> pairwise.t.test(d$x, d$group, pool.sd=FALSE)
Pairwise comparisons using t tests with non-pooled SD
data: d$x and d$group
A B
B 0.03301 -
C 0.00098 0.02032
P value adjustment method: holm
No entanto, para modelos mais complicados, por exemplo, modelos bidirecionais ou modelos lineares com muitos preditores, usar GLS (mínimos quadrados generalizados) e modelar explicitamente as funções de variação é a melhor solução.
E a função de variação não precisa simplesmente ser uma constante diferente em cada grupo; podemos impor estrutura a ele. Por exemplo, podemos modelar a variação como uma potência da média de cada grupo (e, portanto, só precisamos estimar um parâmetro, o expoente), ou talvez como o logaritmo de um dos preditores do modelo. Tudo isso é muito fácil com o GLS (e gls()
no R).
Mínimos quadrados generalizados é IMHO, uma técnica de modelagem estatística muito subutilizada. Em vez de se preocupar com desvios das suposições do modelo, modele esses desvios!
R
, pode ser útil ler minha resposta aqui: Alternativas à ANOVA unidirecional para dados heterocedásticos , que discute alguns desses problemas.