24 Experimentos com delineamento inteiramente casualizados

Nesta sessão iremos usar o R para analisar um experimento em delineamento inteiramente casualizado com apenas um fator. Tal procedimento é também chamado em alguns textos de "análise da variância de simples entrada"(one-way anova). A seguir são apresentados os comandos exemplificando alguns procedimentos usuais para a análise dos dados de um experimento deste tipo que, neste exemplo, envolve um fator com nove níveis (tratamentos). O primeiro passo é ler os dados.

  > ex01 <- read.table("http://www.leg.ufpr.br/~paulojus/dados/exemplo01.txt",
  +     head = T)

Caso não consiga executar o comando acima diretamente com o endereço http utilize um navegador para ir até esta página e copie o arquivo exemplo1.txt para o seu diretório de trabalho. Caso o arquivo esteja em outro diretório deve-se colocar o caminho completo deste diretório no argumento de read.table() acima. A seguir vamos inspecionar o objeto que armazena os dados e seus componentes. Em particular é importante certificar-se que a variável resposta é do tipo numeric e, se os níveis de tratamentos forem qualitativos, a variável indicadora dos tratamentos é do tipo factor . Caso isto não ocorra é necessário transformar as variáveis para estes tipos antes de prosseguir com as análises.

  > head(ex01)

    trat resp
  1   t1  385
  2   t1  323
  3   t1  417
  4   t1  370
  5   t1  437
  6   t1  340

  > is.numeric(ex01$resp)

  [1] TRUE

  > is.factor(ex01$trat)

  [1] TRUE

Portando o objeto ex01 é um data-frame com duas variáveis, sendo uma delas um fator (a variável trat) e a outra uma variável numérica (resp). Vamos iniciar obtendo um rápido resumo dos dados que mostra que este é um experimento "balanceado"com mesmo número de repetições (seis) para cada tratamento. Calculamos também as médias, variâncias e erros padrão das médias para cada tratamento separadamente.

  > summary(ex01)

        trat         resp
   t1     : 6   Min.   :115.0
   t2     : 6   1st Qu.:307.5
   t3     : 6   Median :377.5
   t4     : 6   Mean   :353.5
   t5     : 6   3rd Qu.:417.0
   t6     : 6   Max.   :474.0
   (Other):18

  > ex01.nrep <- with(ex01, tapply(resp, trat, length))
  > ex01.mds <- with(ex01, tapply(resp, trat, mean))
  > ex01.var <- with(ex01, tapply(resp, trat, var))
  > ex01.se <- with(ex01, tapply(resp, trat, function(x) sqrt(var(x)/length(x))))
  > data.frame(Repet = ex01.nrep, Medias = ex01.mds, Variancias = ex01.var,
  +     EP = ex01.se, row.names = paste("trat", 1:9, sep = "-"))

         Repet   Medias Variancias       EP
  trat-1     6 378.6667   1916.267 17.87114
  trat-2     6 431.5000    987.500 12.82900
  trat-3     6 346.3333   3117.867 22.79571
  trat-4     6 293.6667   3494.667 24.13389
  trat-5     6 341.8333   1513.767 15.88378
  trat-6     6 406.0000   1903.600 17.81198
  trat-7     6 164.1667   2173.367 19.03228
  trat-8     6 403.8333   1242.167 14.38846
  trat-9     6 415.6667   1091.067 13.48497

Vamos prosseguir com a análise exploratória com gráficos gerados pelos comandos a seguir e mostrados na Figura 24. O gráfico de esquerda utiliza a função boxcox() do pacote MASS para verificar a necessidade de transformação dos dados o que neste caso não é necessária visto que o valor um está contido no intervalo definido pelas lines tracejadas. A transformação Box-Cox é discutida me mais detalhes em uma outra Seção deste material. O gráfico do meio mostra um boxplot para os dados de cada tratamento, o que deve ser analisado com cautela lembrando que cada boxplot é produzido com apenas seis observações. Optamos aqui por indicar também neste gráfico a média de cada tratamento. O gráfico da direita produzido com stripchart() é uma alternativa ao boxplot para amostras de tamanho pequeno. Na chamada desta função optamos por alterar valores default de alguns argumentos como por exemplo para method="jitter" que provoca pequeno um deslocamento horizontal aleatório dos pontos evitando assim sobreposição de pontos com valores coincidentes ou muito próximos. Ainda neste gráfico acrescentamos as médias e barras que somam e subtraem os erros padrões da média para cada tratamento. Na função arrows() os quatro argumentos iniciais informam coordenadas para as barras, code=3 informa que as "setas"devem ser colocadas em ambas extremidades e angle=90 faz com que a "seta"se torne uma pequena barra horizontal com o tamanho controlado por length.

  > require(MASS)
  > boxcox(resp ~ trat, lambda = seq(0, 3, l = 101), data = ex01)
  > plot(ex01)
  > points(ex01.mds, pch = "x", col = 2, cex = 1.5)
  > with(ex01, stripchart(resp ~ trat, met = "jitter", vert = T, pch = 19))
  > points(ex01.mds, pch = 4, cex = 1.5)
  > arrows(1:9, ex01.mds + ex01.se, 1:9, ex01.mds - ex01.se, angle = 90,
  +     code = 3, length = 0.1)


PIC


Figura 57: Explorando os dados: perfil de verossimilhança do parâmetro da transformação BoxCox (esquerda), boxplot dos dados (centro) e dados com médias e erros padrão para cada tratamento (direita).


É importante notar que as barras simplesmente refletem a variância dos dados dentro da cada tratamento e não são adequadas para detectar diferenças entre tratamentos, o que será discutido mais adiante nesta sessão. Além dos gráficos acima podemos também verificar o pressuposto de homogeneidade de variâncias com o testes de igualdeda de variâncias, como por exemplo, o teste de Bartlett. Neste caso o teste indica variâncias homogêneas. Caso isto não ocorresse uma possível alternativa seria usar o procedimento descrito na Sessão 24.3.

  > bartlett.test(resp ~ trat, data = ex01)
   Bartlett test of homogeneity of variances
  
  data:  resp by trat
  Bartlett's K-squared = 3.6738, df = 8, p-value = 0.8853

Uma vez concluída a análise exploratória e verificada a adequacidade de alguns pressupostos o passo seguinte é ajustar o modelo usando aov() ou lm(). Neste exemplo, por se tratar da análise de um experimento, tipicamente avaliada pelo quadro de análise de variância, optamos por usar aov(). Embora aov() use lm() internamente, os resultados são oranizados internamente de forma conveniente para a efetuar a análise de variância.

  > ex01.mod <- aov(resp ~ trat, data = ex01)
  > ex01.mod
  Call:
     aov(formula = resp ~ trat, data = ex01)
  
  Terms:
                      trat Residuals
  Sum of Squares  332918.1   87201.3
  Deg. of Freedom        8        45
  
  Residual standard error: 44.02053
  Estimated effects may be unbalanced
  > anova(ex01.mod)
  Analysis of Variance Table
  
  Response: resp
            Df Sum Sq Mean Sq F value    Pr(>F)
  trat       8 332918   41615  21.475 5.445e-13
  Residuals 45  87201    1938

Portanto o objeto ex01.mod é uma lista que guarda os resultados da análise para o modelo ajustado. Vamos inspecionar este objeto e seus elementos mais detalhadamente ilustrando como usá-lo para obter a análise dos resultados e extrair elementos para a análise de resíduos. A função names() mostra os elementos da lista e adicionalmente existem funções que extraem elementos do objeto. Duas tipicamente utilizadas são coef() para extrair os coeficientes, residuals() para extrair resíduos e fitted() para valores ajustados, mas há ainda várias outras como effects(), AIC() logLik(), model.tables(), entre outras.

  > names(ex01.mod)
   [1] "coefficients"  "residuals"     "effects"       "rank"          "fitted.values"
   [6] "assign"        "qr"            "df.residual"   "contrasts"     "xlevels"
  [11] "call"          "terms"         "model"
  > coef(ex01.mod)
  (Intercept)      tratt2      tratt3      tratt4      tratt5      tratt6      tratt7
    378.66667    52.83333   -32.33333   -85.00000   -36.83333    27.33333  -214.50000
       tratt8      tratt9
     25.16667    37.00000
  > model.tables(ex01.mod)
  Tables of effects
  
   trat
  trat
       t1      t2      t3      t4      t5      t6      t7      t8      t9
    25.15   77.98   -7.19  -59.85  -11.69   52.48 -189.35   50.31   62.15
  > model.tables(ex01.mod, type = "means")
  Tables of means
  Grand mean
  
  353.5185
  
   trat
  trat
     t1    t2    t3    t4    t5    t6    t7    t8    t9
  378.7 431.5 346.3 293.7 341.8 406.0 164.2 403.8 415.7

O resultado de coef() vai depender da parametrização adotada e definida pelos contrastes. Os valores default e/ou correntes são dados por options()$contrasts. Para fatores qualitativos como no caso deste exemplo a parametrização default corresponde a "contr.treatment" que assinala o valor da média do primeiro tratamento (primeiro nível do fator) ao primeiro coeficiente. Os demais representam a diferença das médias de cada um dos tratamentos à este tratamento de referência.

Uma outra forma de expecificar o modelo para este exemplo é mostrada a seguir com o uso -1 que, para níveis quantititivos corresponde a ajustar um modelo com intercepto igual a zero. No caso de níveis qualitativos como neste exemplo, monta uma matrix do modelo de forma a que cada coeficiente corresponda à média de cada um dos tratamentos. Note que apenas a interpretação dos coeficientes muda e a análise de variância permanece a mesma.

  > ex01.mod1 <- aov(resp ~ trat - 1, data = ex01)
  > coef(ex01.mod1)
    tratt1   tratt2   tratt3   tratt4   tratt5   tratt6   tratt7   tratt8   tratt9
  378.6667 431.5000 346.3333 293.6667 341.8333 406.0000 164.1667 403.8333 415.6667
  > anova(ex01.mod1)
  Analysis of Variance Table
  
  Response: resp
            Df  Sum Sq Mean Sq F value    Pr(>F)
  trat       9 7081587  786843  406.05 < 2.2e-16
  Residuals 45   87201    1938

A parametrização para os coeficientes é determinada pela matriz do modelo e é definida pelo argumento contrasts de options() ou pela função contrasts() que mostra ou atribui a matrix de contrastes a ser utilizada. Fatores são definidos como sendo unordered (por exemplo nívies qualitativos como no caso da análise vista aqui) ou ordered, o que é usado, por exemplo, no caso de níveis quantitativos.

  > options()$contrasts
          unordered           ordered
  "contr.treatment"      "contr.poly"
  > contrasts(ex01$trat)
     t2 t3 t4 t5 t6 t7 t8 t9
  t1  0  0  0  0  0  0  0  0
  t2  1  0  0  0  0  0  0  0
  t3  0  1  0  0  0  0  0  0
  t4  0  0  1  0  0  0  0  0
  t5  0  0  0  1  0  0  0  0
  t6  0  0  0  0  1  0  0  0
  t7  0  0  0  0  0  1  0  0
  t8  0  0  0  0  0  0  1  0
  t9  0  0  0  0  0  0  0  1

Para definir a parametrização a ser utilizada e definida pelos contrastes, pode-se usar outras opções de contrastes já disponibilizadas pelo R tipicamente usando options(). Nos comandos a seguir alteramos a opção para fatores unordered para "contr.sum". Os coeficientes obtidos são diferentes dos obtidos anteriormente sendo o primeiro a média geral e os demais uma comparação da média de cada tratamento contra as médias dos demais. Os resultados da análise de variância permanecem inalterado.

  > options(contrasts = c("contr.sum", "contr.poly"))
  > contrasts(ex01$trat)
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
  t1    1    0    0    0    0    0    0    0
  t2    0    1    0    0    0    0    0    0
  t3    0    0    1    0    0    0    0    0
  t4    0    0    0    1    0    0    0    0
  t5    0    0    0    0    1    0    0    0
  t6    0    0    0    0    0    1    0    0
  t7    0    0    0    0    0    0    1    0
  t8    0    0    0    0    0    0    0    1
  t9   -1   -1   -1   -1   -1   -1   -1   -1
  > coef(lm(resp ~ trat, data = ex01))
  (Intercept)       trat1       trat2       trat3       trat4       trat5       trat6
   353.518519   25.148148   77.981481   -7.185185  -59.851852  -11.685185   52.481481
        trat7       trat8
  -189.351852   50.314815

Os contrastes já definidos no R são listados e descritos a seguir. Além destes outros pacotes podem ter outras definições de contrastes, como em de "contr.sdif" do pacotes MASS. Estes contrastes são terão efeito se o termo -1 não for incluído no modelo pois neste caso os coeficientes são sempre as médias de cada um dos tratamentos, independente da opção de contraste adotada.

Além dos contrastes pré definidos, outros contrastes definidos pelo usuário e atribuídos ao fator em estudo usando a função contrasts(). Retornamos a este tópico com um exemplo na Sessão 24.1.3.

Retornando à análise do exemplo, vaos ver agora alguns gráficos e ferramentas para avaliar o modelo ajustado. Um método associado a plot() produz automaticamente gráficos de resíduos para objetos das classes lm e aov conforme ilustrado na Figura 24 produzida com o comando plot(ex01.mod).


PIC


Figura 58: Gráficos para diagnóstico do ajuste do modelo.


Além dos gráficos "pré-preparados"pelo R, o usuário pode obter outros que desejar extraindo a informação necessária do objeto que contém o ajuste do modelo. Na Figura 24 mostramos quatro gráficos: resíduos padronizados versus valores preditos, boxplot, histograma dos resíduos padronizados e qqplot() dos resíduos. Para isto obtemos os resíduos padronizados dividindo os resíduos do modelo pela raiz quadrada da variância do termo de erro.

  > ex01.res <- resid(ex01.mod)
  > respad <- ex01.res/sqrt(sum(ex01.res^2)/ex01.mod$df.res)
  > plot(fitted(ex01.mod), respad, xlab = "valores ajustados", ylab = "resíduos")
  > title("Resíduos Padronizados vs \n Valores Preditos")
  > boxplot(respad)
  > title("Resíduos Padronizados")
  > hist(respad, main = "Histograma dos resíduos padronizados")
  > qqnorm(ex01.res, ylab = "Residuos", main = NULL)
  > qqline(ex01.res)
  > title("Gráfico Normal de \n Probabilidade dos Resíduos")


PIC


Figura 59: Gráficos de resíduos.


Um teste de normalidade dos residuos pode ser efetuado como indicado a seguir.

  > shapiro.test(ex01.res)
   Shapiro-Wilk normality test
  
  data:  ex01.res
  W = 0.9716, p-value = 0.2263

24.1 Comparando tratamentos

Uma das formas possíveis formas de interpretar os resultados no caso de efeito de tratamentos significativos é utilizar algum procedimento de comparações de tratamentos após verificar o resultado da anova, o que justifica o termo às vezes utilizado que descreve tais procedimentos como comparações post-hoc.

A questão do uso de comparações de tratamentos é polêmica no meio estatístico e não vamos aqui entrar em tal discussâo. Neste sessão vamos ilustrar três procedimentos deixando a cargo do leitor o julgamento de qual procedimento é mais adequado para o problema em questão. Os procedimentos discutidos a seguir correspondem a três possiveis abordagens ao problema de comparação de mais de duas médias, sendo eles: (i) teste-t para comparações duas a duas, (ii) teste de Tukey e (iii) contrastes e contrastes ortogonais. O primeiro caso se desdobra em mais opções uma vez que permite que os valores p sejam ou não ajustados, e caso sejam, por diferentes métodos.

Os procedimentos mostrados aqui são implementados em pacotes básicos do R. O pacote multcomp disponibiliza uma extensa lista de procedimentos adicionais de comparações múltiplas e alguns procedimentos específicos podem ainda ser encontrados em outros pacotes do R.

24.1.1 Comparações de pares

A função pairwise.t.test() calcula todas as possíveis comparações entre dois grupos, podendo ser vista como uma extensão ao teste-t para duas amostras, retornando o valor-p para cada comparação. A principal diferença é que o nível de significância deve ser corrigido para garantir o nivel de significância conjunto para todas comparações. O argumento p.adjust.method da função permite o usuário escolher entre diferentes métodos propostos para ajustar o nível de significância sendo o default o prodedimento proposto por Holm, que é uma modificação ao ajuste de Bonferroni, que também é disponível utilizando através do argumento p.adj="bonferroni". Mais detalhes podem ser encontrados na documentação da função.

  > with(ex01, pairwise.t.test(resp, trat))

   Pairwise comparisons using t tests with pooled SD
  
  data:  resp and trat
  
     t1      t2      t3      t4      t5      t6      t7      t8
  t2 0.65049 -       -       -       -       -       -       -
  t3 1.00000 0.03768 -       -       -       -       -       -
  t4 0.03768 6.4e-05 0.65049 -       -       -       -       -
  t5 1.00000 0.02345 1.00000 0.83853 -       -       -       -
  t6 1.00000 1.00000 0.39692 0.00160 0.28829 -       -       -
  t7 2.5e-09 3.8e-12 1.8e-07 0.00019 3.2e-07 8.2e-11 -       -
  t8 1.00000 1.00000 0.45676 0.00203 0.33686 1.00000 1.0e-10 -
  t9 1.00000 1.00000 0.18109 0.00048 0.11918 1.00000 2.5e-11 1.00000
  
  P value adjustment method: holm

24.1.2 Teste de Tukey

O teste Tukey de comparações múltiplas é implementado na função TukeyHSD(). A saída em formato texto do teste de Tukey é mostrada a seguir e plot(ex01.HSD) produz o gráfico mostrado na Figura 24.1.2. As saídas da função mostram intervalos de confiança para as diferenças entre pares de médias.

  > ex01.HSD <- TukeyHSD(ex01.mod, ordered = TRUE)
  > ex01.HSD

    Tukey multiple comparisons of means
      95% family-wise confidence level
      factor levels have been ordered
  
  Fit: aov(formula = resp ~ trat, data = ex01)
  
  $trat
              diff        lwr       upr     p adj
  t4-t7 129.500000  46.719034 212.28097 0.0002153
  t5-t7 177.666667  94.885701 260.44763 0.0000004
  t3-t7 182.166667  99.385701 264.94763 0.0000002
  t1-t7 214.500000 131.719034 297.28097 0.0000000
  t8-t7 239.666667 156.885701 322.44763 0.0000000
  t6-t7 241.833333 159.052367 324.61430 0.0000000
  t9-t7 251.500000 168.719034 334.28097 0.0000000
  t2-t7 267.333333 184.552367 350.11430 0.0000000
  t5-t4  48.166667 -34.614299 130.94763 0.6203900
  t3-t4  52.666667 -30.114299 135.44763 0.5040619
  t1-t4  85.000000   2.219034 167.78097 0.0401018
  t8-t4 110.166667  27.385701 192.94763 0.0024139
  t6-t4 112.333333  29.552367 195.11430 0.0018566
  t9-t4 122.000000  39.219034 204.78097 0.0005599
  t2-t4 137.833333  55.052367 220.61430 0.0000730
  t3-t5   4.500000 -78.280966  87.28097 1.0000000
  t1-t5  36.833333 -45.947633 119.61430 0.8721075
  t8-t5  62.000000 -20.780966 144.78097 0.2886707
  t6-t5  64.166667 -18.614299 146.94763 0.2479215
  t9-t5  73.833333  -8.947633 156.61430 0.1146645
  t2-t5  89.666667   6.885701 172.44763 0.0247945
  t1-t3  32.333333 -50.447633 115.11430 0.9342210
  t8-t3  57.500000 -25.280966 140.28097 0.3855262
  t6-t3  59.666667 -23.114299 142.44763 0.3369467
  t9-t3  69.333333 -13.447633 152.11430 0.1671352
  t2-t3  85.166667   2.385701 167.94763 0.0394343
  t8-t1  25.166667 -57.614299 107.94763 0.9849417
  t6-t1  27.333333 -55.447633 110.11430 0.9749062
  t9-t1  37.000000 -45.780966 119.78097 0.8693183
  t2-t1  52.833333 -29.947633 135.61430 0.4998060
  t6-t8   2.166667 -80.614299  84.94763 1.0000000
  t9-t8  11.833333 -70.947633  94.61430 0.9999286
  t2-t8  27.666667 -55.114299 110.44763 0.9730043
  t9-t6   9.666667 -73.114299  92.44763 0.9999849
  t2-t6  25.500000 -57.280966 108.28097 0.9836416
  t2-t9  15.833333 -66.947633  98.61430 0.9993743


PIC


Figura 60: Resultados do tete de Tukey.


Visualizações mais convenientes dos resultados podem ser obtidas com operações sobre o objeto resultante, tal como a usualmente adotada de listar as médias em ordem descrescente e indicar com letras as diferenças significativas ou não entre estas médias. Vamos ilustrar aqui uma possivel forma de obter tal visualização. Inicialmente vamos obter a DMS (diferença mínima significativa). No caso deste experimento balanceado, isto é, o mesmo número de repetições em cada tratamento, o intervalo de confiança para cada diferença é o mesmo e a DMS é portanto comum e dada por metade da amplitude do intervalo.

  > dms <- unname(0.5 * diff(ex01.HSD[[1]][1, 2:3]))
  > dms
  [1] 82.78097

O passso seguinte é ordenar as médias deforma decrescente e verificar as diferenças significativas. O código abaixo é uma (mas certamente não a única) maneira de indicar as diferenças significativas código de letras usual na literatura.

  > ex01.mds.ord <- sort(ex01.mds, decreasing = TRUE)
  > i <- pos <- letra <- 1
  > letras <- character(nlevels(ex01$trat))
  > while (i <= nlevels(ex01$trat)) {
  +     print(letters[letra])
  +     ind <- (ex01.mds.ord[i] - (ex01.mds.ord[-(1:i)])) < dms
  +     pos.i <- i + sum(ind)
  +     if (pos.i > pos) {
  +         letras.vec <- rep(" ", length(letras))
  +         letras.vec[i:pos.i] <- letters[letra]
  +         letras <- paste(letras, letras.vec, sep = "")
  +         pos <- pos.i
  +         letra <- letra + 1
  +     }
  +     i <- i + 1
  + }
  [1] "a"
  [1] "b"
  [1] "c"
  [1] "c"
  [1] "c"
  [1] "c"
  [1] "d"
  [1] "d"
  [1] "d"
  > data.frame(medias = ex01.mds.ord, diferencas = letras)
       medias diferencas
  t2 431.5000       a
  t9 415.6667       ab
  t6 406.0000       ab
  t8 403.8333       ab
  t1 378.6667       ab
  t3 346.3333        bc
  t5 341.8333        bc
  t4 293.6667         c
  t7 164.1667          d

Neste caso o procedimento é simples pois para um experimento balanceado e pelo teste de Tukey tem-se apenas um único valor de DMS. O algorítmo deve ser modificado e generalizado para outras situações ou pode-se usar funções de pacotes como multcompLatters do pacote multcompView.

24.1.3 Contrastes e contrastes ortogonais

Na análise de experimentos pode-se ter interesse em estudar determinadas comparações entre as médias que podem ser especificadas pelo usuário na forma de contrastes, que são um caso particular das funções estimáveis para o modelo. Vamos iniciar revendo definições.

Seja o modelo linear escrito na forma matricial Y = + ϵ onde Y é a variável resposta, X a matrix do modelo, β o vetor de p parâmetros (coeficientes) e ϵ o vetor de erros. Uma combinação linear dos coeficientes da forma pλpβp onde λ = [λ1,p] é um vetor de constantes é dita uma função estimável para o dado modelo se λ pode ser escrita como uma combinação linear das linhas da X. Um contraste é um caso especial de função estimável em que a soma das constantes é nula, isto é, pode ser escrito como pcpβp onde pcp = 0.

No que se segue vamos ver como obter estimativas de contrastes de interesse no R, onde fórmulas lineares são usadas para definir as matrizes do modelo usadas no ajuste de modelos lineares e lineares generalizados. No caso de fatores (qualitativos) a matriz X do modelo não é definida unicamente para um mesmo experimento, podendo ser escrita de diversas formas alternativas que irão produzir a ajustes equivalentes. Tais formas são definidas pela escolha de contrastes ou funções estimáveis que definirão a interpretação dos coeficientes β do modelo. Portanto, se o interesse é apenas na análise de variância a particular forma adotada é irrelevante. Por outro lado, a escolha deve ser adequada se os coeficientes devem ser interpretados.

Ao ajustar um modelo as estimativas de contrastes podem ser obtidas de duas formas:

Vamos discutir aqui algums idéias iniciais sobre como implementar a segunda forma. Como na análise de contrastes os coeficientes passam a ser diretamente interpretados, passamos a usar lm() no ajuste do modelo.

Uma classe especial de contrastes é a de contrastes ortogonais. Um conjunto de contrastes ortogonais tem a propriedade de que as soma dos produtos dos coeficientes de qualquer par de contrastes deste conjunto é nula. Contrastes ortogonais são particularmente interessantes pois permitem desdobrar (particionar) a soma de quadrados de tratamentos um parcelas referentes a cada um dos contrastes. Isto permite que cada contraste seja testado diretamente por um teste t (ou o equivalente teste F).

Com nove tratamentos é possível definir oito contrastes ortogonais com cada um deles sendo associado a um dos graus de liberdade dos tratamentos. A definição destes contrastes não é única e deve refletir comparações relevantes para o problema em questão, assegurando-se que a ortogonalidade seja mantida o que garante que a soma das somas de quadrados dos contrastes seja equivalente à soma de quadrados total dos tratamentos. Para obter o desdobramento abordamos a modelagem como um problema de regressão múltipla onde os contrastes definem variáveis quantitativas a serem incluídas no modelo que é ajustado com lm(). Neste exemplo vamos considerar o seguinte conjunto de contrastes entre as médias dos tratamentos que são especificados nas linhas de uma matriz como se segue.

  > c1 <- rbind(c(2, 2, 2, -1, -1, -1, -1, -1, -1), c(2, -1, -1, rep(0,
  +     6)), c(0, 1, -1, rep(0, 6)), c(rep(0, 3), c(2, 2, -1, -1, -1, -1)),
  +     c(rep(0, 3), c(1, -1), rep(0, 4)), c(rep(0, 5), c(1, 1, -1, -1)),
  +     c(rep(0, 5), c(1, -1, 0, 0)), c(rep(0, 5), c(0, 0, 1, -1)))
  > c1

       [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
  [1,]    2    2    2   -1   -1   -1   -1   -1   -1
  [2,]    2   -1   -1    0    0    0    0    0    0
  [3,]    0    1   -1    0    0    0    0    0    0
  [4,]    0    0    0    2    2   -1   -1   -1   -1
  [5,]    0    0    0    1   -1    0    0    0    0
  [6,]    0    0    0    0    0    1    1   -1   -1
  [7,]    0    0    0    0    0    1   -1    0    0
  [8,]    0    0    0    0    0    0    0    1   -1

O próximo passo é fazer com que a matriz do modelo seja montada pelo R de forma que os coeficientes reflitam os contrastes desejados. Para isto associamos ao fator que representa os tratamentos (trat no exemplo) o atributo contrast contendo a inversa generalizada obtida por ginv() do pacote MASS. A analise de variância deste modelo é a mesma obtida anteriormente. entretanto os coeficientes são agora dados pela média geral seguida pelas estimativas de cada um dos oito contrastes definidos que que podem ser testadas diretamente pelo teste-t usando o comando summary().

  > c1.ginv <- ginv(c1)
  > colnames(c1.ginv) <- paste("contr", 1:8, sep = "")
  > contrasts(ex01$trat) <- c1.ginv
  > mod1 <- lm(resp ~ trat, data = ex01)
  > anova(mod1)

  Analysis of Variance Table
  
  Response: resp
            Df Sum Sq Mean Sq F value    Pr(>F)
  trat       8 332918   41615  21.475 5.445e-13
  Residuals 45  87201    1938

  > summary(mod1)

  Call:
  lm(formula = resp ~ trat, data = ex01)
  
  Residuals:
     Min     1Q Median     3Q    Max
  -85.67 -33.29   4.75  33.17  85.67
  
  Coefficients:
              Estimate Std. Error t value Pr(>|t|)
  (Intercept)   353.52       5.99  59.014  < 2e-16
  tratcontr1    287.83      76.25   3.775 0.000466
  tratcontr2    -20.50      44.02  -0.466 0.643682
  tratcontr3     85.17      25.41   3.351 0.001638
  tratcontr4   -118.67      62.25  -1.906 0.063029
  tratcontr5    -48.17      25.41  -1.895 0.064503
  tratcontr6   -249.33      35.94  -6.937 1.26e-08
  tratcontr7    241.83      25.41   9.515 2.41e-12
  tratcontr8    -11.83      25.41  -0.466 0.643748
  
  Residual standard error: 44.02 on 45 degrees of freedom
  Multiple R-squared: 0.7924, Adjusted R-squared: 0.7555
  F-statistic: 21.48 on 8 and 45 DF,  p-value: 5.445e-13

Nos comandos a seguir visualizamos os mesmos resultados de uma forma alternativa, usando model.matrix() para montar a matrix de covariáveis da forma desejada, onde excluímos o intercepto (primeira coluna) e, para visualização adequadoa dos resultados, trocamos os nomes das colunas. A este data-frame adicionamos os dados e ajustamos o modelo de regressão com lm(). A função anova() sobre o modelo ajustado exibe a soma de quadrados decomposta entre os contrastes agora testados pelo teste F que é equivalente ao teste-t mostrado acima pois cada contraste possui um grau de liberdade. Note que a soma delas corresponde a soma de quadrados de tratamentos mostrada no ajuste inicial do modelo o os coeficientes são os mesmos.

  > ex01co <- data.frame(model.matrix(resp ~ trat, ex01)[, -1])
  > names(ex01co) <- paste("Contraste", 1:8)
  > ex01co$resp <- ex01$resp
  > mod2 <- lm(resp ~ ., data = ex01co)
  > av2 <- anova(mod2)
  > av2

  Analysis of Variance Table
  
  Response: resp
                Df Sum Sq Mean Sq F value    Pr(>F)
  Contraste 1  1  27616   27616 14.2512  0.000466
  Contraste 2  1    420     420  0.2169  0.643682
  Contraste 3  1  21760   21760 11.2292  0.001638
  Contraste 4  1   7041    7041  3.6334  0.063029
  Contraste 5  1   6960    6960  3.5917  0.064503
  Contraste 6  1  93251   93251 48.1217 1.264e-08
  Contraste 7  1 175450  175450 90.5405 2.409e-12
  Contraste 8  1    420     420  0.2168  0.643748
  Residuals     45  87201    1938

  > sum(av2$Sum[1:8])

  [1] 332918.1

  > coef(mod2)

    (Intercept) Contraste 1 Contraste 2 Contraste 3 Contraste 4 Contraste 5
      353.51852     287.83333     -20.50000      85.16667    -118.66667     -48.16667
  Contraste 6 Contraste 7 Contraste 8
     -249.33333     241.83333     -11.83333

Os coeficiente retornados equivalem à aplicar os contrastes desejados sobre as médias dos tratamentos. Pode-se ainda visualizar os contrastes assinalados ao fator trat através da inversa generalizada.

  > drop(c1 %*% ex01.mds)

  [1]  287.83333  -20.50000   85.16667 -118.66667  -48.16667 -249.33333  241.83333
  [8]  -11.83333

  > fractions(contrasts(ex01$trat))

     contr1 contr2 contr3 contr4 contr5 contr6 contr7 contr8
  t1   1/9    1/3      0      0      0      0      0      0
  t2   1/9   -1/6    1/2      0      0      0      0      0
  t3   1/9   -1/6   -1/2      0      0      0      0      0
  t4 -1/18      0      0    1/6    1/2      0      0      0
  t5 -1/18      0      0    1/6   -1/2      0      0      0
  t6 -1/18      0      0  -1/12      0    1/4    1/2      0
  t7 -1/18      0      0  -1/12      0    1/4   -1/2      0
  t8 -1/18      0      0  -1/12      0   -1/4      0    1/2
  t9 -1/18      0      0  -1/12      0   -1/4      0   -1/2

Uma forma alternativa talvez mais direta e conveniente de obter a decomposição da soma de quadrados de tratamentos entre os contrastes é com o uso de aov() e summary() utilizando o argumento split

  > mod3 <- aov(resp ~ trat, data = ex01)
  > summary(mod3, split = list(trat = 1:8))

              Df Sum Sq Mean Sq F value    Pr(>F)
  trat         8 332918   41615 21.4752 5.445e-13
    trat: C1   1  27616   27616 14.2512  0.000466
    trat: C2   1    420     420  0.2169  0.643682
    trat: C3   1  21760   21760 11.2292  0.001638
    trat: C4   1   7041    7041  3.6334  0.063029
    trat: C5   1   6960    6960  3.5917  0.064503
    trat: C6   1  93251   93251 48.1217 1.264e-08
    trat: C7   1 175450  175450 90.5405 2.409e-12
    trat: C8   1    420     420  0.2168  0.643748
  Residuals   45  87201    1938

Nota: A atribuição do atributo contrast ao fator não terá efeito sobre a construção da matrix do modelo caso o termo de intercepto esteja retirado na definição do modelo, por exemplo, se o modelo acima fosse definido por resp   trat - 1.

Para cancelar a atribuição dos contrastes a um fator e retornar a definida por option() basta fazer atribuir a valor NULL.

  > contrasts(ex01$trat) <- NULL

Interpretando os contrastes: a interpretação dos contrastes vai depender dos valores dos coeficientes definidos na matriz do contrastes (matriz c1 no exemplo). Por exemplo suponha que desejamos obter contrastes de forma não só a obter testes de significância mas também obter estimativas dos contrastes com interpretação desejada. No exemplo, para comparar médias μi (ou efeitos ti) dos tratamentos com efeitos estimados do contrastes na mesma escala da médias do tratamentos poderíamos definir c1 da forma a seguir. Todos os resultados e testes de significância (estatístics de testes e p-valores) permanecem inalterados e apenas os valores dos efeitos estimados são diferentes

  > c1 <- rbind(c(1/3, 1/3, 1/3, -1/6, -1/6, -1/6, -1/6, -1/6, -1/6), c(1,
  +     -0.5, -0.5, rep(0, 6)), c(0, 1, -1, rep(0, 6)), c(rep(0, 3), c(0.5,
  +     0.5, -0.25, -0.25, -0.25, -0.25)), c(rep(0, 3), c(1, -1), rep(0,
  +     4)), c(rep(0, 5), c(0.5, 0.5, -0.5, -0.5)), c(rep(0, 5), c(1, -1,
  +     0, 0)), c(rep(0, 5), c(0, 0, 1, -1)))
  > fractions(c1)

       [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
  [1,]  1/3  1/3  1/3 -1/6 -1/6 -1/6 -1/6 -1/6 -1/6
  [2,]    1 -1/2 -1/2    0    0    0    0    0    0
  [3,]    0    1   -1    0    0    0    0    0    0
  [4,]    0    0    0  1/2  1/2 -1/4 -1/4 -1/4 -1/4
  [5,]    0    0    0    1   -1    0    0    0    0
  [6,]    0    0    0    0    0  1/2  1/2 -1/2 -1/2
  [7,]    0    0    0    0    0    1   -1    0    0
  [8,]    0    0    0    0    0    0    0    1   -1

  > c1.ginv <- ginv(c1)
  > colnames(c1.ginv) <- rownames(c1) <- paste("contr", 1:8, sep = "")
  > contrasts(ex01$trat) <- c1.ginv
  > mod4 <- lm(resp ~ trat, data = ex01)
  > summary(mod4)

  Call:
  lm(formula = resp ~ trat, data = ex01)
  
  Residuals:
     Min     1Q Median     3Q    Max
  -85.67 -33.29   4.75  33.17  85.67
  
  Coefficients:
              Estimate Std. Error t value Pr(>|t|)
  (Intercept)   353.52       5.99  59.014  < 2e-16
  tratcontr1     47.97      12.71   3.775 0.000466
  tratcontr2    -10.25      22.01  -0.466 0.643682
  tratcontr3     85.17      25.41   3.351 0.001638
  tratcontr4    -29.67      15.56  -1.906 0.063029
  tratcontr5    -48.17      25.41  -1.895 0.064503
  tratcontr6   -124.67      17.97  -6.937 1.26e-08
  tratcontr7    241.83      25.41   9.515 2.41e-12
  tratcontr8    -11.83      25.41  -0.466 0.643748
  
  Residual standard error: 44.02 on 45 degrees of freedom
  Multiple R-squared: 0.7924, Adjusted R-squared: 0.7555
  F-statistic: 21.48 on 8 and 45 DF,  p-value: 5.445e-13

  > coef(mod4)

  (Intercept)  tratcontr1  tratcontr2  tratcontr3  tratcontr4  tratcontr5  tratcontr6
    353.51852    47.97222   -10.25000    85.16667   -29.66667   -48.16667  -124.66667
   tratcontr7  tratcontr8
    241.83333   -11.83333

Definindo contrastes com funções do pacote gmodels . Este pacote oferece várias funções auxiliares que facilitam o uso e a apresentação dos resultados em formatos por vezes convenientes. No exemplo a seguir vamos repetir a obtenção dos resultados para os contrastes definidos ma matrix c1 conforme definida anteriormente.

  > require(gmodels)
  > mod5 <- aov(resp ~ trat, data = ex01, contrast = list(trat = make.contrasts(c1)))
  > summary(mod5, split = list(trat = 1:8))

              Df Sum Sq Mean Sq F value    Pr(>F)
  trat         8 332918   41615 21.4752 5.445e-13
    trat: C1   1  27616   27616 14.2512  0.000466
    trat: C2   1    420     420  0.2169  0.643682
    trat: C3   1  21760   21760 11.2292  0.001638
    trat: C4   1   7041    7041  3.6334  0.063029
    trat: C5   1   6960    6960  3.5917  0.064503
    trat: C6   1  93251   93251 48.1217 1.264e-08
    trat: C7   1 175450  175450 90.5405 2.409e-12
    trat: C8   1    420     420  0.2168  0.643748
  Residuals   45  87201    1938

  > fit.contrast(mod5, "trat", c1)

               Estimate Std. Error    t value     Pr(>|t|)
  tratcontr1   47.97222   12.70763  3.7750713 4.660336e-04
  tratcontr2  -10.25000   22.01027 -0.4656918 6.436823e-01
  tratcontr3   85.16667   25.41527  3.3510042 1.638352e-03
  tratcontr4  -29.66667   15.56361 -1.9061560 6.302888e-02
  tratcontr5  -48.16667   25.41527 -1.8951863 6.450255e-02
  tratcontr6 -124.66667   17.97131 -6.9369836 1.263698e-08
  tratcontr7  241.83333   25.41527  9.5152781 2.408674e-12
  tratcontr8  -11.83333   25.41527 -0.4655994 6.437479e-01

Experimentos desbalanceados: finalmente vale ressaltar que o exemplo acima tratou de um experimento balanceado, isto é, com o mesmo número de repetições para cada tratamento e no caso de desbalanceamento ajustes são necessários na definição dos contrastes.

24.2 Recursos adicionais para comparações múltiplas

Na sessão anterior discutimos a comparação post-hoc de tratmentos utilizando funções como pairwise.t.text() e TukeyHSD implementadas no conjunto de pacotes básicos do R.

Outros procedimentos sãqo implementados em pacotes contribuídos do R. Entre estes encontra-se os pacotes multcomp e multcompView que implementam diversos outros procedimentos e gráficos para visualizações dos resultados. Vale notar que estes pacotes devem ser instalados com a opção dependencies=TRUE para garantir plena funcionalidade pois suas funções dependem de diversos outros pacotes.

  > install.packages("multcompView", dep = TRUE)
  > require(multcomp)
  > require(multcompView)

Para ilustrar o uso desta pacote vamos efetuar novamente o teste de Tukey visto acima porém agora utilizando cálculos e gráficos gerados por funções destes pacotes, cujos resultados, embora iguais, são apresentados em forma diferente do visto anteriormente. A indicação de letras para diferenças entre pares de tratamentos mostrada a seguir requer que TukeyHSD seja invocada sem a ordenação dos tratamentos e uma representação visual é dada na Figura 24.2.

  > multcompLetters(TukeyHSD(ex01.mod)$trat[, 4])

    t2   t3   t4   t5   t6   t7   t8   t9   t1
   "a" "bc"  "b" "bc" "ac"  "d" "ac" "ac" "ac"

  > multcompBoxplot(resp ~ trat, data = ex01, compFn = "TukeyHSD", decreasing = FALSE)


PIC


Figura 61: Visualização dos resultados do teste de Tukey com função do pacote multicompView


24.3 Análise para variâncias não homogêneas

No caso de variâncias não homogêneas em experimentos inteiramente casualizados a função oneway.test() pode ser utilizada nas análises. Uma outra alternativa é a análise não paramétrica da Kruskall-Wallis implementada por kruskal.test().