ez icon indicating copy to clipboard operation
ez copied to clipboard

Type3 SS in ezANOVA not working in 4.2.0+

Open mychan24 opened this issue 12 years ago • 6 comments
trafficstars

I am calculating a mixed-ANOVA with within and between subject variables. My groups are not completely equal in Ns, so I am trying to use Type 3 SS.

Starting from version 4.2.0, type=1 2 or 3 produces the same results. Whereas if I switch back to 4.1.1, it gives a more stringent results with using type 3.

Does anyone else experience the same issue?

mychan24 avatar Oct 30 '13 22:10 mychan24

I know it's been a long time since this first message, however I am still experiencing this in version 4.4.0. I was wondering if this was planning on being addressed.

mdefende avatar Oct 03 '19 19:10 mdefende

I wasn't able to reproduce this when it was originally reported. I should have posted a message saying so. A user just emailed me separately with a reproducible example in which they were ignoring the standard result from ezANOVA(..., type=3) and instead looking at the result in ezANOVA(..., type=3, return_aov=TRUE)$aov, which I now see does indeed have an incorrect result. @mychan24 obviously you may not recall at all, but @mdefende do you recall if this latter usage matches what you were observing?

mike-lawrence avatar Feb 11 '20 13:02 mike-lawrence

Yes, it looks like the reported sums of squares are not the same between the ANOVA and aov outputs for the ezANOVA(..., type = 3, return_aov=TRUE) call. One of the people I was working with determined the $ANOVA output was incorrect due to contrasts not being set properly for Type III sums of squares by default. Default is to use treatments contrasts (contr.treatment) which are not orthogonal, but Type III sums of squares have to have orthogonal contrasts to work correctly. He said using sums contrasts by calling options(contrasts=c(‘contr.sum', ‘contr.poly’)) will set the correct contrasts. This does indeed cause the reported sums of squares to be the same between $aov and $ANOVA outputs.

mdefende avatar Feb 12 '20 00:02 mdefende

Hm, I can't replicate your colleague's observation that setting the contrasts option makes the SS's of $ANOVA and $aov match:

library(tidyverse)
library(ez)
#> Registered S3 methods overwritten by 'lme4':
#>   method                          from
#>   cooks.distance.influence.merMod car 
#>   influence.merMod                car 
#>   dfbeta.influence.merMod         car 
#>   dfbetas.influence.merMod        car

#use the ANT dataset for demonstration
data(ANT)

#add an imbalanced second between-Ss variable
ANT$handedness = factor(ifelse(
    as.numeric(ANT$subnum)%%3==1
    , 'l'
    , 'r'
))

#show the imbalanced design
ezDesign(
      data = ANT
    , y = subnum
    , x = group
    , col = handedness
)


#set treatment contrasts and run ezANOVA
options(contrasts = c('contr.treatment','contr.poly'))
out_treatment = ezANOVA(
      data = ANT
    , wid = subnum
    , dv = rt
    , between = .(group,handedness)
    , type = 3
    , detailed = T
    , return_aov = TRUE
)
#> Warning: Data is unbalanced (unequal N per group). Make sure you specified
#> a well-considered value for the type argument to ezANOVA().
#> Warning: Collapsing data to cell means. *IF* the requested effects are a
#> subset of the full design, you must use the "within_full" argument, else
#> results may be inaccurate.
#> Coefficient covariances computed by hccm()

#combine, compare, and store for looking at later
tibble(
    effect = out_treatment$ANOVA$Effect
    , ANOVA_ssn =  out_treatment$ANOVA$SSn
) %>% 
    dplyr::full_join(
        tibble(
            effect = str_trim(dimnames(summary(out_treatment$aov)[[1]])[[1]])
            , aov_ssn = summary(out_treatment$aov)[[1]]$Sum
        )
        , by = 'effect'
    ) %>% 
    dplyr::mutate(
        nearly_equal = near(ANOVA_ssn,aov_ssn)
    ) ->
    treatment_compared

#set sum contrasts and run ezANOVA
options(contrasts = c('contr.sum','contr.poly'))
out_sum = ezANOVA(
    data = ANT
    , wid = subnum
    , dv = rt
    , between = .(group,handedness)
    , type = 3
    , detailed = T
    , return_aov = TRUE
)
#> Warning: Data is unbalanced (unequal N per group). Make sure you specified
#> a well-considered value for the type argument to ezANOVA().

#> Warning: Collapsing data to cell means. *IF* the requested effects are a
#> subset of the full design, you must use the "within_full" argument, else
#> results may be inaccurate.
#> Coefficient covariances computed by hccm()

#combine, compare, and store for looking at later
tibble(
    effect = out_sum$ANOVA$Effect
    , ANOVA_ssn =  out_sum$ANOVA$SSn
) %>% 
    dplyr::full_join(
        tibble(
            effect = str_trim(dimnames(summary(out_sum$aov)[[1]])[[1]])
            , aov_ssn = summary(out_sum$aov)[[1]]$Sum
        )
        , by = 'effect'
    ) %>% 
    dplyr::mutate(
        nearly_equal = near(ANOVA_ssn,aov_ssn)
    ) ->
    sum_compared

#check if contrast type affects whether $ANOVA and $aov match
print(treatment_compared)
#> # A tibble: 5 x 4
#>   effect              ANOVA_ssn    aov_ssn nearly_equal
#>   <chr>                   <dbl>      <dbl> <lgl>       
#> 1 (Intercept)      2965387.      NA        NA          
#> 2 group                 98.8    141.       FALSE       
#> 3 handedness             0.0959   0.000933 FALSE       
#> 4 group:handedness      17.5     17.5      TRUE        
#> 5 Residuals             NA      139.       NA
print(sum_compared)
#> # A tibble: 5 x 4
#>   effect              ANOVA_ssn    aov_ssn nearly_equal
#>   <chr>                   <dbl>      <dbl> <lgl>       
#> 1 (Intercept)      2965387.      NA        NA          
#> 2 group                 98.8    141.       FALSE       
#> 3 handedness             0.0959   0.000933 FALSE       
#> 4 group:handedness      17.5     17.5      TRUE        
#> 5 Residuals             NA      139.       NA


#try setting contrasts explicitly ----

#set treatment contrasts and run ezANOVA
contrasts(ANT$group) = 'contr.treatment'
contrasts(ANT$handedness) = 'contr.treatment'
out_treatment = ezANOVA(
    data = ANT
    , wid = subnum
    , dv = rt
    , between = .(group,handedness)
    , type = 3
    , detailed = T
    , return_aov = TRUE
)
#> Warning: Data is unbalanced (unequal N per group). Make sure you specified
#> a well-considered value for the type argument to ezANOVA().

#> Warning: Collapsing data to cell means. *IF* the requested effects are a
#> subset of the full design, you must use the "within_full" argument, else
#> results may be inaccurate.
#> Coefficient covariances computed by hccm()

#combine, compare, and store for looking at later
tibble(
    effect = out_treatment$ANOVA$Effect
    , ANOVA_ssn =  out_treatment$ANOVA$SSn
) %>% 
    dplyr::full_join(
        tibble(
            effect = str_trim(dimnames(summary(out_treatment$aov)[[1]])[[1]])
            , aov_ssn = summary(out_treatment$aov)[[1]]$Sum
        )
        , by = 'effect'
    ) %>% 
    dplyr::mutate(
        nearly_equal = near(ANOVA_ssn,aov_ssn)
    ) ->
    treatment_compared


#set sum contrasts and run ezANOVA
contrasts(ANT$group) = 'contr.sum'
contrasts(ANT$handedness) = 'contr.sum'
out_sum = ezANOVA(
    data = ANT
    , wid = subnum
    , dv = rt
    , between = .(group,handedness)
    , type = 3
    , detailed = T
    , return_aov = TRUE
)
#> Warning: Data is unbalanced (unequal N per group). Make sure you specified
#> a well-considered value for the type argument to ezANOVA().

#> Warning: Collapsing data to cell means. *IF* the requested effects are a
#> subset of the full design, you must use the "within_full" argument, else
#> results may be inaccurate.
#> Coefficient covariances computed by hccm()

#combine, compare, and store for looking at later
tibble(
    effect = out_sum$ANOVA$Effect
    , ANOVA_ssn =  out_sum$ANOVA$SSn
) %>% 
    dplyr::full_join(
        tibble(
            effect = str_trim(dimnames(summary(out_sum$aov)[[1]])[[1]])
            , aov_ssn = summary(out_sum$aov)[[1]]$Sum
        )
        , by = 'effect'
    ) %>% 
    dplyr::mutate(
        nearly_equal = near(ANOVA_ssn,aov_ssn)
    ) ->
    sum_compared


#check if contrast type affects whether $ANOVA and $aov match
print(treatment_compared)
#> # A tibble: 5 x 4
#>   effect           ANOVA_ssn    aov_ssn nearly_equal
#>   <chr>                <dbl>      <dbl> <lgl>       
#> 1 (Intercept)      499580.    NA        NA          
#> 2 group                12.7  141.       FALSE       
#> 3 handedness            9.49   0.000933 FALSE       
#> 4 group:handedness     17.5   17.5      TRUE        
#> 5 Residuals            NA    139.       NA
print(sum_compared)
#> # A tibble: 5 x 4
#>   effect              ANOVA_ssn    aov_ssn nearly_equal
#>   <chr>                   <dbl>      <dbl> <lgl>       
#> 1 (Intercept)      2965387.      NA        NA          
#> 2 group                 98.8    141.       FALSE       
#> 3 handedness             0.0959   0.000933 FALSE       
#> 4 group:handedness      17.5     17.5      TRUE        
#> 5 Residuals             NA      139.       NA

Created on 2020-02-13 by the reprex package (v0.3.0)

mike-lawrence avatar Feb 13 '20 15:02 mike-lawrence

Though that does remind me that ezANOVA internally sets options(contrasts=c('contr.sum','contr.poly') and I should really warn users about that (I'd even forgotten about it and was confused for a bit why setting the contrasts via options myself was yielding identical results).

mike-lawrence avatar Feb 13 '20 15:02 mike-lawrence

Hey @mike-lawrence, not entirely recalling what I did, but pretty sure I was calling the $aov and extracting numbers from that instead. I think maybe just adding these info to the README would be sufficient for those who are digging around to understand why the output is not what they thought.

I have mostly switched to lmer and afex, but appreciate the development you put into this :)

mychan24 avatar Feb 17 '20 21:02 mychan24