---
title: "A complete workflow with real data: SES and school context in High School and Beyond"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{A complete workflow with real data}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include = FALSE}
has_mlmrev <- requireNamespace("mlmRev", quietly = TRUE)
knitr::opts_chunk$set(collapse = TRUE, comment = "#>", fig.width = 6.5,
                      fig.height = 4, eval = has_mlmrev)
```

```{r, eval = !has_mlmrev, echo = FALSE, results = "asis"}
cat("*This vignette uses the `Hsb82` data from the 'mlmRev' package;",
    "install it to run the code.*")
```

This vignette analyses a classic cross-level interaction with public data:
does the within-school relationship between students' socioeconomic status
(SES) and mathematics achievement depend on the average SES of the school?
The data are the 1982 High School and Beyond subsample analysed by
Raudenbush and Bryk (2002): 7,185 students in 160 schools.

## Model

`cses` is student SES centred at the school mean, so its coefficient is a
purely within-school slope. `meanses` is the school mean SES, a cluster-level
moderator. Following Raudenbush and Bryk, the model also lets the SES slope
differ by school sector.

```{r model}
library(mlmoderator)
library(lme4)
data("Hsb82", package = "mlmRev")

fit <- lmer(mAch ~ cses * meanses + cses * sector + (1 + cses | school),
            data = Hsb82)
```

## Probing the interaction

```{r summary}
mlm_summary(fit, pred = "cses", modx = "meanses")
```

Because `meanses` is constant within schools, the default probe points
(mean and ±1 SD) are computed across the 160 schools rather than across
students, so large schools do not dominate them.

Tests use Satterthwaite degrees of freedom by default. Inference for a
cross-level interaction draws its information from the clusters, so the
relevant degrees of freedom are on the order of the number of schools, not
the number of students:

```{r df-compare}
sapply(c("satterthwaite", "kenward-roger", "between", "residual"),
       function(m) {
         r <- mlm_summary(fit, "cses", "meanses", jn = FALSE,
                          df_method = m)$interaction
         round(c(SE = r$se, df = r$df, p = r$p), 5)
       })
```

With 160 schools the choice hardly matters here. It matters a great deal
with few clusters: in a simulation with 10 clusters and no true interaction,
the `"residual"` rule (students minus fixed effects, the default before
mlmoderator 0.3.0) rejected in 10.0% of 400 replications at the nominal 5%
level, while Satterthwaite rejected in 5.5% and the between-cluster rule in
5.75%.

## Plots

```{r plot}
mlm_plot(fit, pred = "cses", modx = "meanses",
         x_label = "Student SES (school-centred)",
         y_label = "Mathematics achievement",
         legend_title = "School mean SES")
```

```{r jn}
plot(mlm_jn(fit, pred = "cses", modx = "meanses"))
```

## How much do school slopes vary beyond the moderator?

The interaction describes how the *average* SES slope changes with school
SES. Individual schools still differ around that average:

```{r decomp}
vd <- mlm_variance_decomp(fit, pred = "cses", modx = "meanses")
vd
plot(vd)
```

The confidence intervals describe the average slope at each value of
`meanses`; the prediction intervals describe the slope to expect in a new
school with that mean SES. They are wider because school mean SES
explains only part of the between-school variation in SES slopes.

## Is the interaction driven by a few schools?

```{r loco}
sens <- mlm_sensitivity(fit, pred = "cses", modx = "meanses",
                        df_method = "between")
sens
plot(sens)
```

Dropping any single school leaves the interaction positive and
significant. A few schools move the estimate by more than the screening
cutoff and are worth inspecting, but none changes the conclusion.

## What this workflow does not do

* The diagnostics describe the fitted model. They do not address
  unmeasured confounding of the interaction; school mean SES is not randomly
  assigned, and the interaction is an association unless further assumptions
  hold.
* Prediction intervals treat the random-slope variance as known and assume
  normally distributed random slopes.
* The DFBETA cutoff flags clusters for inspection. It is not a test.

## Reference

Raudenbush, S. W., & Bryk, A. S. (2002). *Hierarchical linear models:
Applications and data analysis methods* (2nd ed.). Sage.
