Desenho Experimental e Análise Avançada de Dados Ecológicos
2025-11-18
I’ve (purposely) postponing mentioning model assumptions
Given we followed the model comparison approach (Judd et al. 2017), it makes sense to discuss model assumptions towards the end, once we understand the basics of building statistical models
Now it is finally time to understand model assumptions: what are they? what happens when they are violated? what can we do to address violations?
Many assumptions can be empirically assessed, but some are theoretical
Generally speaking, the model should be properly specified to meet all the theoretical assumptions
Independent samples models: The independent variable/s define independent samples (for non-repeated measures models)
Repeated measures models: the independent variable/s define/s repeated measures (for repeated measures ANOVA or linear mixed models)
Mixed designs: one/some IV/s define independent samples and another/others repeated measures (split-plot/mixed ANOVAs or linear mixed models)
For quantitative variables
Inspected by looking at scatterplots of DV ~ IV
Only applicable for categorical predictors if there are interaction not featured in the model
With quick and dirty base R graph:
With pretty ggplot2 graph:
With pretty ggplot2 graph:
Ways to address violations:
Log transform the DV and IV
Compute the square root of the DV and IVs
Note: transforming the data means H0 and H1 will refer to the transformed data
Ways to address violations:
Shapiro-Wilk’s test:
Kolmogorov-Smirnov’s test with Lilliefors correction:
Visual inspection of the histogram or density graph of the standardized residuals
Visual inspection of the qq-plot of standardized residuals
In base R:
Shapiro-Wilk normality test
data: errors
W = 0.99144, p-value = 0.04502
[1] 342
With the performance package:
Lilliefors (Kolmogorov-Smirnov) normality test
data: errors
D = 0.040585, p-value = 0.1859
Not available in base R, requires nortest
There is no significant evidence of non-normality (for α = .050)
Working with scaled residuals (z scores) means we know they’ll have a mean of zero and standard deviation of one
This means we can easily scale the graphs to range from minus three to plus three (M +/- 3 x SD) or some other multiple of the SD
In base R:
With ggplot2:
In base R:
With ggplot2:
Interpretation:
I reckon it’s mostly normal, with slight deviations in the extreme ends of the tails
Note: graphical inspection is subjective, just be consistent
Ways to address violations:
Log transform the DV, and/or IVs:
Compute the square root of the DV and/or IVs
Box-cox transform the DV
Note: transforming the data means H0 and H1 will refer to the transformed data
Ways to address violations:
Fit a non-linear model:
Fit a non-parametric model (these have different H0 and H1)
Report it, and do nothing (specially when N is large)?
\(\sigma_1^2 = \sigma_2^2 = \sigma_{\cdots} = \sigma_i^2\)
Independent samples models: The variance of the DV is the same in all combinations of the levels of the IV/s
Mixed designs: The variances of the DV is the same in all combinations of the levels of the between-units IV/s for all levels of the repeated measures IV/s
Models with only repeated measures IV/s: only applicable to linear mixed models, repeated measures ANOVAs do not have that assumption (they assume sphericity, see next slides)
Tested/inspected with:
In base R:
With ggplot2:
With ggplot2:
Interpretation (in regard to homo/heteroscedasticity):
We see a funneling pattern, with our model showing a better fit when predicting lower values for the DV, than when predicting higher values
We make more errors predicting heavier body masses
There is more variability in higher body masses when given as a function of bill length
Get predictions:
Interpretation:
Same as before
We make more errors predicting heavier body masses
There is more variability in higher body masses when given as a
Levene’s test only works for categorical IV/s
Let’s fit a One-Way ANOVA testing for differences in body mass between species
Using the car package:
Ways to address violations:
Fit a robust model
Correct the test statistic (with categorical predictors one can apply the Welch or Brown-Forsythe correction)
Ways to address violations:
\(\sigma_{A-B}^2 = \sigma_{A-C}^2 = \sigma_{B-C}^2\)
The variance of the differences between each measurement of the DV (e.g., A, B, C) is the same:
Only applicable when (at least one of) the repeated measures IV/s has k > 2
Only applicable to repeated measures ANOVAs or split-plot ANOVAs (i.e., not applicable to mixed models)
Ways to test/probe for violations:
Looking at the value of Epsilon (ε < 0.7 suggests a violation)
With Mauchly’s test of sphericity
Ways to address violations:
Apply Greenhouse-Geisser, Huynd-Feldt, or Lower-Bound correction
Fit a linear mixed model (mixed())
Fit a robust model
Note: afex automatically performs Mauchly’s tests (when applicable) and automatically applies the Greenhouse-Geisser correction
Anova Table (Type 3 tests)
Response: Log10MR
Effect df MSE F pes p.value
1 Species 1, 253 0.03 288.52 *** .533 <.001
2 Stage 1, 253 0.02 757.70 *** .750 <.001
3 Species:Stage 1, 253 0.02 16.84 *** .062 <.001
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '+' 0.1 ' ' 1
afex::aov_4() or afex::aov_car() do not report a violation of sphericity it means Mauchly’s test of sphericity yields no significant evidence (for α = .05) for a violation.OK: Data seems to be spherical (p > .999).
The independent variables are independent of one another (i.e., they are not correlated):
Inspected by looking at a correlation matrix with all IVs
Inspected by looking at scatter plots of each IV as a function of another
Inspected by looking at VIF and/or Tolerance:
Fitting a multiple linear regression (quantitative IVs):
| Term | VIF | VIF_CI_low | VIF_CI_high | SE_factor | Tolerance | Tolerance_CI_low | Tolerance_CI_high |
|---|---|---|---|---|---|---|---|
| bill_length_mm | 1.865090 | 1.623085 | 2.201090 | 1.365683 | 0.5361671 | 0.4543202 | 0.6161108 |
| bill_depth_mm | 1.611292 | 1.418853 | 1.892145 | 1.269367 | 0.6206201 | 0.5285008 | 0.7047946 |
| flipper_length_mm | 2.673338 | 2.277269 | 3.192223 | 1.635034 | 0.3740642 | 0.3132613 | 0.4391224 |
The errors (residuals) are not autocorrelated (we cannot predict an error based on the error for the previous observation)
More discussed/explored in regards to time-series models
Tested with the Durbin-watson test
Not necessarily a formal assumption, but the OLS estimator is very sensitive to them
Different criteria are debated/recommended in the literature:
Visual exploration of scatter, residual, and/or Q-Q plots
For a great discussion and tutorial see Lüdecke et al
OK: No outliers detected.
- Based on the following method and threshold: cook (0.841).
- For variable: (Whole model)
Ways to address outliers:
Pre-register an objective cutoff according to some metric/s to spot residuals
Fit a model on the entire dataset, and fit a model with the outliers removed, then check if the pattern of results holds
Fit a model that’s robust against outliers (e.g., robustbase::lmrob(), robustlmm:rlmer())
Like other statistical tests, assumption tests have limitations:
Power (the ability to detect an effect if there is one) increases with sample size
For small sample sizes they often underestimate violations, and for large sample sizes they often overestimate (or flag small violations of little import)
Thus, visual inspection is often recommended (e.g., Judd et al 2017)
see Packagesee Packagesee Packagesee PackageIf results from the robust models yield the same pattern of results as those from an OLS linear model, then it is unlikely the violation of assumptions ill cause an erroneous inference
If results from the robust models show a different pattern of results than those from an OLS linear model, it signals assumptions were violated, and results from the OLS model should be suspected
Or just use robust statistics instead of the “traditional” OLS models (see Field & Wilcox 2017)
I know…
There are some ways to visually inspect a model for fit and relevant assumptions
If you run performance::check_model() you can visually inspect your model for all, or most, relevant assumptions (by looking at a single dashboard)
In base R plot(model) will also show relevant graphs (one a time)
With performance:
In base R:
Do nothing, but report the violation/s, and that the results may be unreliable
Transform the data to fix the violation/s (see above)
Adjust the test statistic and/or degrees of freedom to correct for the violation/s (see above)
Use a statistical procedure that’s robust against the violation/s (more modern approach, see above)
Look at the pretty graphs in check_model() and tell me if you see anything wrong
Large violations of the assumptions should inspire theoretical reflection
I haven’t put much emphasis in the minimal sample size for each model
In reality, sample size is dictated by practical constraints and should be informed by power analysis
Still, the more variables, and the more complex model you have, the bigger your sample should be
I don’t like rules of thumb…but Jenkins and Quintana-Ascencio 2020 found N < 8 is too small for inference, in regression, even with very little error, and N < 25 may be too small with standard conditions (regardless, power may be too low)