Destacando resultados significativos de comparações múltiplas não paramétricas em boxplots


9

Tenho gráficos de caixa de 13 grupos que mostro em um gráfico. Os grupos têm populações desequilibradas e não são normalmente distribuídas. Quero mostrar quais pares são estatisticamente semelhantes (ou seja, têm valor de p kruskal.test <0,05) colocando a, b, c, etc. em cima das caixas correspondentes. Aqui está um pseudo-código para mostrar o que tenho:

A = c(1, 5, 8, 17, 16, 3, 24, 19, 6) 
B = c(2, 16, 5, 7, 4, 7, 3) 
C = c(1, 1, 3, 7, 9, 6, 10, 13) 
D = c(2, 15, 2, 9, 7) 
junk = list(g1=A, g2=B, g3=C, g4=D) 
boxplot(junk) 

Aqui está um gráfico que achei que faz o que eu quero (exceto que eu tenho 13 grupos em uma linha):

Respostas:


7

O código mais simples que me vem à cabeça é mostrado abaixo. Tenho certeza de que existem funções já existentes para fazer isso no CRAN, mas estou com preguiça de procurá-las, mesmo no R-seek .

dd <- data.frame(y=as.vector(unlist(junk)), 
                 g=rep(paste("g", 1:4, sep=""), unlist(lapply(junk, length))))

aov.res <- kruskal.test(y ~ g, data=dd)
alpha.level <- .05/nlevels(dd$g)  # Bonferroni correction, but use 
                                  # whatever you want using p.adjust()

# generate all pairwise comparisons
idx <- combn(nlevels(dd$g), 2)

# compute p-values from Wilcoxon test for all comparisons
pval.res <- numeric(ncol(idx))
for (i in 1:ncol(idx))
  # test all group, pairwise
  pval.res[i] <- with(dd, wilcox.test(y[as.numeric(g)==idx[1,i]], 
                                      y[as.numeric(g)==idx[2,i]]))$p.value

# which groups are significantly different (arranged by column)
signif.pairs <- idx[,which(pval.res<alpha.level)]

boxplot(y ~ g, data=dd, ylim=c(min(dd$y)-1, max(dd$y)+1))
# use offset= to increment space between labels, thanks to vectorization
for (i in 1:ncol(signif.pairs))
    text(signif.pairs[,i], max(dd$y)+1, letters[i], pos=4, offset=i*.8-1)

Aqui está um exemplo do que o código acima produziria (com diferenças significativas entre os quatro grupos):

insira a descrição da imagem aqui

Em vez do teste de Wilcoxon, pode-se confiar no procedimento implementado na kruskalmc()função do pacote pgirmess (veja uma descrição do procedimento usado aqui ).

Além disso, verifique as dicas R de Rudolf Cardinal sobre R: gráficos básicos 2 (consulte, em particular, Outro gráfico de barras, com anotações ).


Obrigado, chl. Como não sou estatístico, preciso aprender mais sua resposta, mas parece que ele faz o que eu preciso.
Ilik

Se houver algo incerto, não hesite em perguntar. Não há muita coisa estatística aqui: usei testes de Wilcoxon para comparações de grupos em pares e corrigi os valores de p individuais para limitar o risco geral de falso positivo para 5%. O pacote npmc inclui recursos adicionais para lidar com comparações múltiplas não paramétricas, mas também há a estrutura de moedas . O resto é puramente código R usando gráficos R básicos; isso poderia ser feito com retículo ou ggplot2 também.
chl

Peço desculpas pela minha ignorância nas estatísticas. Então, eu tentei o seu código e notei que você calcula o kruskal.test, mas não usa o resultado (aov.res). Agora entendo que o wilcox.test é um caso especial para o kruskal para duas amostras. Mas então tentei mudar os valores nos meus grupos para torná-los (intuitivamente) diferentes e ver o que surgia. A = c (10, 50, 18, 17, 16, 31, 24, 19, 6) B = c (10, 50, 18, 17, 16, 30, 25, 18, 7) C = c (1, 1, 3, 7, 9, 6, 10, 13) D = c (200, 158, 206, 119, 77). g1 e g2 agora são significativamente diferentes? e G3 e G4 não são? não sei se entendi o porquê.
Ilik

@ Ilik Algo deu errado no meu código (a with(dd,instrução estava no lugar errado, resultando em um teste estranho!). Obrigado por capturar isso! Sim, eu não uso os resultados do teste KW, mas é sempre uma boa ideia verificá-lo primeiro, caso contrário, vários testes post-hoc não teriam sentido (ou pelo menos sugeririam uma espionagem de dados). Observe que corrigi o código e nada se mostrou significativo, mas deixei a imagem original por uma questão de clareza, com resultados significativos.
chl

Para qualquer pessoa interessada, alterei um pouco o código para escrever os resultados no boxplot: MyText = rep ('', nlevels (ddg))for(iin1:ncol(signif.pairs))MyText[signif.pairs[,i]]=paste(MyText[signif.pairs[,i]],letters[i],sep=)text(c(1:nlevels(ddg)), rep (max (dd g)), MeuTexto)y)+1,neueveeus(dd
Ilik
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.