Author: Sonja Sahebzad
September 17, 2026
Air quality changes from day to day, while static summaries can hide important patterns.
The app turns the built-in R airquality data into a guided, interactive experience.
Every input produces a visible reactive result. The live Shiny version adds filters, hover details, zoom, summaries, and model-based predictions.
The app compares an additive model with a plausible temperature by wind interaction. Five-fold cross-validation evaluates prediction error.
aq <- na.omit(airquality)
aq$MonthName <- factor(month.abb[aq$Month])
set.seed(2026)
fold <- sample(rep(1:5, length.out = nrow(aq)))
cv_rmse <- function(formula) {
predicted <- rep(NA_real_, nrow(aq))
for (i in 1:5) {
model <- lm(formula, data = aq[fold != i, ])
predicted[fold == i] <- predict(model, aq[fold == i, ])
}
sqrt(mean((aq$Ozone - predicted)^2))
}
round(c(
additive = cv_rmse(Ozone ~ Temp + Wind + MonthName),
interaction = cv_rmse(Ozone ~ Temp * Wind + MonthName)
), 2)
additive interaction
22.35 21.49
The deployed application repeats the comparison with fixed, reproducible cross-validation folds and uses the lower-error model.
The patterns are descriptive associations from New York in one summer in 1973. The predictions are educational and are not current health guidance.