
Diagnose and Remedy Model Assumptions
agriDesignR contributors
Source:vignettes/diagnostics-remedies.Rmd
diagnostics-remedies.Rmd
library(agriDesignR)
data("tomato_rcbd", package = "agriDesignR")Check design and response data
The tomato data contain an RCBD with an intentionally incomplete or
unbalanced layout and a plant-density covariate.
check_design() reports missingness, cell counts, blocking,
and response characteristics before model fitting.
design <- check_design(
data = tomato_rcbd,
response = "fruit_weight",
treatment = "treatment",
block = "block",
covariates = "plant_density"
)
design$balance_status
#> [1] "balanced"
design$response_audit
#> $n_total
#> [1] 20
#>
#> $n_observed
#> [1] 18
#>
#> $n_unique
#> [1] 18
#>
#> $n_na
#> [1] 2
#>
#> $pct_na
#> [1] 10
#>
#> $is_numeric
#> [1] TRUE
#>
#> $is_integer_like
#> [1] FALSE
#>
#> $has_negatives
#> [1] FALSE
#>
#> $has_zeros
#> [1] FALSE
#>
#> $pct_zeros
#> [1] 0
#>
#> $is_proportion
#> [1] FALSE
#>
#> $has_proportion_boundary
#> [1] FALSE
#>
#> $is_percentage
#> [1] FALSE
#>
#> $is_binary
#> [1] FALSE
#>
#> $max_value
#> [1] 135.68
#>
#> $min_value
#> [1] 93.86
#>
#> $skewness
#> [1] -0.07780486
#>
#> $suggested_family
#> [1] "gaussian (standard normal linear model)"
design$warnings
#> character(0)Fit and inspect assumptions
Use the fixed-effects engine here to show a classical RCBD analysis with the covariate. In a real study, choose fixed versus random block effects from the sampling and randomization plan, not from a p-value.
fit <- fit_experiment(
data = tomato_rcbd,
response = "fruit_weight",
treatment = "treatment",
block = "block",
covariates = "plant_density",
engine = "lm"
)
fit$assumptions$overall_status
#> [1] "ACCEPTABLE_WITH_CAUTIONS"
fit$assumptions$normality$message
#> [1] "Mild deviation from normality (W = 0.861, p = 0.0128, skewness = 0.93). ANOVA F-tests remain robust under moderate sample sizes."
fit$assumptions$homoscedasticity$message
#> [1] "Equal variance across treatment groups confirmed (Variance ratio max/min = 2.37x, Levene p = 0.996)."The audit is a screening aid. Residual plots, study-specific knowledge, and the consequences for the estimand remain necessary before changing model.
with(fit, {
graphics::plot(
stats::fitted(model),
stats::residuals(model),
xlab = "Fitted values",
ylab = "Residuals"
)
graphics::abline(h = 0, lty = 2, col = "grey40")
})
Evaluate a transformation as sensitivity analysis
remedy() can fit a transformed response or a
heterogeneous-variance model. The automatic option is inspectable:
compare returned fits, assumptions, and scientific interpretation before
selecting a final analysis.
boxcox_fit <- remedy(fit, method = "boxcox")
boxcox_fit$remedy_type
#> [1] "Log Transformation (ln(y))"
boxcox_fit$comparison_table
#> Metric Original_Model
#> 1 Model Formula fruit_weight ~ treatment + plant_density
#> 2 Engine / Family base (gaussian)
#> 3 AIC 124.62
#> 4 BIC 129.96
#> 5 Residual Normality (Shapiro p) 0.0128
#> 6 Variance Ratio (max/min) 2.37
#> 7 Overall Health Status ACCEPTABLE_WITH_CAUTIONS
#> Remedied_Model
#> 1 fruit_weight_trans ~ treatment + plant_density
#> 2 base (gaussian)
#> 3 -45.85
#> 4 -40.51
#> 5 0.0203
#> 6 2.97
#> 7 ACCEPTABLE_WITH_CAUTIONS
boxcox_fit$verdict
#> [1] "[OK] REMEDY SUBSTANTIALLY IMPROVED: Residual metrics improved significantly and are now well within acceptable limits for robust inference."For count responses, consider a Poisson or negative-binomial model rather than transforming counts solely to satisfy Gaussian residual diagnostics. For repeated measurements, model within-subject dependence explicitly. Do not use a remedy to hide flawed randomization or turn a post-hoc choice into a confirmatory claim.