Type: Package
Title: Hierarchical Linear Modeling with Visualization and Decomposition
Version: 0.1.0
Description: Provides functions for visualization and decomposition in hierarchical linear models (HLM) for applications in education, psychology, and the social sciences. Includes variance decomposition for two-level and three-level data structures following Snijders and Bosker (2012, ISBN:9781849202015), intraclass correlation (ICC) estimation and design effect computation as described in Shrout and Fleiss (1979) <doi:10.1037/0033-2909.86.2.420>, and contextual effect decomposition via the Mundlak (1978) <doi:10.2307/1913646> specification distinguishing within- and between-cluster components. Supports visualization of random slopes and cross-level interactions following Hofmann and Gavin (1998) <doi:10.1177/014920639802400504> and Hamaker and Muthen (2020) <doi:10.1037/met0000239>. Multilevel models are estimated using 'lme4' (Bates et al., 2015 <doi:10.18637/jss.v067.i01>). An optional 'Shiny' application enables interactive exploration of model components and parameter variation. The implementation follows the multilevel modeling framework of Raudenbush and Bryk (2002, ISBN:9780761919049).
License: MIT + file LICENSE
Encoding: UTF-8
Language: en-US
Depends: R (≥ 4.1.0)
Imports: dplyr, ggplot2 (≥ 3.4.0), lme4, scales, stats
Suggests: shiny, spelling, testthat (≥ 3.0.0)
Config/testthat/edition: 3
RoxygenNote: 7.3.3
URL: https://github.com/causalfragility-lab/hlmLab
BugReports: https://github.com/causalfragility-lab/hlmLab/issues
NeedsCompilation: no
Packaged: 2026-04-10 20:02:12 UTC; Subir
Author: Subir Hait ORCID iD [aut, cre]
Maintainer: Subir Hait <haitsubi@msu.edu>
Repository: CRAN
Date/Publication: 2026-04-16 10:50:02 UTC

Contextual effect for a Level-1 predictor (Mundlak decomposition)

Description

Given a multilevel model with a within-cluster centered predictor and its cluster-mean counterpart (Mundlak specification), this function extracts the within- and between-cluster effects and computes the contextual effect (between - within).

Usage

hlm_context(model, x_within, x_between)

Arguments

model

A fitted lmerMod model.

x_within

Name of the within-cluster centered predictor (string).

x_between

Name of the cluster-mean predictor (string).

Value

An object of class hlm_context, which is a tibble with:

effect_type

Within, between, or contextual.

estimate

Estimate of the effect.

se

Standard error (approximate for contextual).

Examples

# Build a small toy dataset (no external data needed)
set.seed(1)
n_schools <- 8
n_students <- 12
school_id <- rep(seq_len(n_schools), each = n_students)
SES_raw   <- rnorm(n_schools * n_students)
SES_mean  <- rep(tapply(SES_raw, school_id, mean), each = n_students)
SES_c     <- SES_raw - SES_mean
math_score <- 50 + 2 * SES_c + 3 * SES_mean + rep(rnorm(n_schools, sd = 2), each = n_students) +
              rnorm(n_schools * n_students)
toy <- data.frame(math_score = math_score, SES_c = SES_c,
                  SES_mean = SES_mean, school_id = school_id)


m   <- lme4::lmer(math_score ~ SES_c + SES_mean + (1 | school_id), data = toy)
ctx <- hlm_context(m, x_within = "SES_c", x_between = "SES_mean")
ctx
hlm_context_plot(ctx)


Convenience wrapper to plot contextual effects

Description

Convenience wrapper to plot contextual effects

Usage

hlm_context_plot(object)

Arguments

object

An object of class hlm_context.

Value

A ggplot object.


Multilevel variance decomposition (within/between/longitudinal)

Description

Decomposes a continuous variable into between-cluster, and within-cluster components (2-level), or into between-cluster (B), between-person (P), and within-person (W) components for longitudinal 3-level data.

Usage

hlm_decompose(data, var, cluster, id = NULL, time = NULL)

Arguments

data

A data frame.

var

Name of the focal variable (string).

cluster

Name of the cluster ID variable (e.g., school/classroom).

id

Optional person ID variable for longitudinal data.

time

Optional time variable (not required for the algebra, but noted in the output for clarity).

Details

This is primarily a teaching tool: it shows how total variance is partitioned across levels.

Value

An object of class hlm_decompose with components:

data

Original data with added decomposition columns.

summary

A tibble summarizing variance components and shares.

Examples

# 2-level example (students in schools)
set.seed(2)
toy <- data.frame(
  math_score = rnorm(80, mean = 50, sd = 10),
  school_id  = rep(letters[1:8], each = 10)
)
hlm_decompose(toy, var = "math_score", cluster = "school_id")

# 3-level longitudinal example (waves within students within schools)

toy3 <- data.frame(
  math_score = rnorm(120, 50, 10),
  school_id  = rep(letters[1:4], each = 30),
  student_id = rep(seq_len(24), each = 5)
)
hlm_decompose(toy3, var = "math_score", cluster = "school_id",
              id = "student_id", time = NULL)


Longitudinal three-level variance decomposition (B-P-W)

Description

Convenience wrapper around hlm_decompose() for 3-level data: clusters (e.g., schools), persons within clusters, and repeated measures within persons over time.

Usage

hlm_decompose_long(data, var, cluster, id, time = NULL)

Arguments

data

A data frame.

var

Name of the focal variable (string).

cluster

Cluster ID (e.g., school/classroom) (string).

id

Person ID within cluster (string).

time

Optional time variable (string); stored in the output for reference but not required for the algebra.

Value

An object of class hlm_decompose with between-cluster (B), between-person (P), and within-person (W) variance components and shares.

Examples

set.seed(4)
toy_long <- data.frame(
  math_score = rnorm(120, 50, 10),
  school_id  = rep(letters[1:4], each = 30),
  student_id = rep(seq_len(24), each = 5),
  wave       = rep(seq_len(5), times = 24)
)
hlm_decompose_long(data = toy_long,
                   var     = "math_score",
                   cluster = "school_id",
                   id      = "student_id",
                   time    = "wave")

Intraclass correlation and design effect from a random-intercept model

Description

Computes the intraclass correlation (ICC) and, optionally, a design effect from a random-intercept multilevel model fitted with lme4::lmer().

Usage

hlm_icc(model, cluster_size = NULL)

Arguments

model

A fitted lmerMod object with at least one random intercept.

cluster_size

Optional scalar giving the average cluster size, used to compute the design effect. If NULL, the design effect is not computed.

Value

An object of class hlm_icc with components:

icc

Estimated intraclass correlation.

deff

Design effect (if cluster_size supplied).

re_var

Random intercept variance.

resid_var

Residual variance.

Examples

set.seed(3)
toy <- data.frame(
  math_score = rnorm(80, 50, 10),
  SES        = rnorm(80),
  school_id  = rep(seq_len(8), each = 10)
)

library(lme4)
m <- lmer(math_score ~ SES + (1 | school_id), data = toy)
hlm_icc(m, cluster_size = 10)


Teaching plot for intraclass correlation (ICC)

Description

Visualizes the intraclass correlation by plotting the between- and within-cluster variance components as a stacked bar. This is intended as a teaching diagram to help students see how the ICC reflects the share of variance that lies between clusters.

Usage

hlm_icc_plot(model, cluster_size = NULL)

Arguments

model

A fitted lmerMod model with a random intercept.

cluster_size

Optional scalar giving the average cluster size, passed to hlm_icc() to compute the design effect.

Value

A ggplot object.


Geometry of a cross-level interaction (random slopes fan plot)

Description

Produces a "fan plot" of predicted lines for each cluster to illustrate a cross-level interaction (random slope) in a multilevel model.

Usage

hlm_xint_geom(model, x_within, cluster, n_points = 20, n_clusters = 20)

Arguments

model

A fitted lmerMod model with a random slope term of the form (x_within | cluster).

x_within

Name of the Level-1 predictor with a random slope (string).

cluster

Name of the clustering factor (string).

n_points

Number of points to plot along the x-axis. Defaults to 20.

n_clusters

Maximum number of clusters to display (sampled) for clarity.

Value

A ggplot object showing predicted lines by cluster.

Examples

# Small toy example using inline data (runs automatically)
set.seed(42)  # seed set by the *user* in the example, not inside the function
n_schools <- 10
n_students <- 15
school_id <- rep(seq_len(n_schools), each = n_students)
SES_c <- rnorm(n_schools * n_students)
u0 <- rep(rnorm(n_schools, sd = 0.5), each = n_students)
u1 <- rep(rnorm(n_schools, sd = 0.3), each = n_students)
math_score <- 50 + 2 * SES_c + u0 + u1 * SES_c + rnorm(n_schools * n_students, sd = 1)
toy <- data.frame(math_score = math_score, SES_c = SES_c, school_id = school_id)


m <- lme4::lmer(math_score ~ SES_c + (SES_c | school_id), data = toy)
hlm_xint_geom(m, x_within = "SES_c", cluster = "school_id")


Plot method for hlm_context objects

Description

Produces an error-bar plot of within, between, and contextual effects with 95% confidence intervals. Intended as a teaching diagram.

Usage

## S3 method for class 'hlm_context'
plot(x, ...)

Arguments

x

An object of class hlm_context.

...

Not used.

Value

A ggplot object.


Plot method for hlm_decompose objects

Description

Produces a simple bar chart of variance shares across components, suitable for teaching how variance is partitioned across levels.

Usage

## S3 method for class 'hlm_decompose'
plot(x, ...)

Arguments

x

An object of class hlm_decompose.

...

Not used.

Value

A ggplot object.