Title: Partial Eta-Squared for Crossed, Nested, and Mixed Linear Mixed Models
Version: 0.2.0
Description: Computes partial eta-squared effect sizes for fixed effects in linear mixed models fitted with the 'lme4' package. Supports crossed, nested, and mixed (crossed-and-nested) random effects structures with any number of grouping factors. Mixed designs handle cases where grouping factors are simultaneously crossed with some variables and nested within others (e.g., photos nested within models, but both crossed with participants). Random slope variances are translated to the outcome scale using a variance decomposition approach, correctly accounting for predictor scaling and interaction terms. Both general and operative effect sizes are provided. Methods are based on Correll, Mellinger, McClelland, and Judd (2020) <doi:10.1016/j.tics.2019.12.009>, Correll, Mellinger, and Pedersen (2022) <doi:10.3758/s13428-021-01687-2>, and Rights and Sterba (2019) <doi:10.1037/met0000184>.
License: MIT + file LICENSE
URL: https://github.com/bcohen0901/pecanr
BugReports: https://github.com/bcohen0901/pecanr/issues
Encoding: UTF-8
RoxygenNote: 7.3.3
Imports: lme4
Suggests: spelling, testthat (≥ 3.0.0)
Config/testthat/edition: 3
Language: en-US
NeedsCompilation: no
Packaged: 2026-03-27 01:24:50 UTC; brandoncohen
Author: Brandon Cohen ORCID iD [aut, cre], Joshua Correll ORCID iD [aut, ths]
Maintainer: Brandon Cohen <brandon.cohen-1@colorado.edu>
Repository: CRAN
Date/Publication: 2026-04-12 02:20:02 UTC

pecanr: Partial Eta-Squared for Crossed, Nested, and Mixed Linear Mixed Models

Description

Computes partial eta-squared effect sizes for fixed effects in linear mixed models fitted with the 'lme4' package. Supports crossed, nested, and mixed (crossed-and-nested) random effects structures with any number of grouping factors. Mixed designs handle cases where grouping factors are simultaneously crossed with some variables and nested within others (e.g., photos nested within models, but both crossed with participants). Random slope variances are translated to the outcome scale using a variance decomposition approach, correctly accounting for predictor scaling and interaction terms. Both general and operative effect sizes are provided. Methods are based on Correll, Mellinger, McClelland, and Judd (2020) doi:10.1016/j.tics.2019.12.009, Correll, Mellinger, and Pedersen (2022) doi:10.3758/s13428-021-01687-2, and Rights and Sterba (2019) doi:10.1037/met0000184.

Author(s)

Maintainer: Brandon Cohen brandon.cohen-1@colorado.edu (ORCID)

Authors:

See Also

Useful links:


Batch Calculate Partial Eta-Squared for Multiple Effects

Description

Calculates partial eta-squared for all fixed effects (excluding the intercept) in a model.

Usage

batch_eta2p(
  model,
  data,
  design = c("crossed", "nested", "mixed"),
  subj_var = NULL,
  item_var = NULL,
  cross_vars = NULL,
  nest_vars = NULL,
  operative = FALSE,
  verbose = FALSE
)

Arguments

model

A fitted model object from lme4::lmer().

data

Data frame used to fit the model.

design

Character string: "crossed", "nested", or "mixed". Use "mixed" when the model contains both crossed and nested random effects (e.g., photos nested within models, but both crossed with participants).

subj_var

Character string specifying the subject/participant grouping variable. Retained for backward compatibility; prefer cross_vars.

item_var

Character string specifying the item/stimulus grouping variable. Retained for backward compatibility; prefer cross_vars.

cross_vars

Character vector of grouping variable names that are crossed with each other and with the nested hierarchy (e.g., c("participant") or c("participant", "rater")). Supersedes subj_var and item_var when provided.

nest_vars

Character vector of nesting variables ordered from lowest to highest level (e.g., c("photo", "model") when photos are nested within models). Required for design = "nested" or design = "mixed".

operative

Logical. If TRUE, calculates operative effect size (excludes variance components that do not contribute to the SE of the effect). Default is FALSE.

verbose

Logical. If TRUE, prints detailed results. Default is TRUE.

Value

A data frame with one row per effect containing:

effect

Name of the fixed effect.

eta2p

Partial eta-squared value.

effect_level

Effect level (nested/mixed designs only).

variance_effect

Variance attributed to the effect.

variance_error

Error variance used in the denominator.

type

"general" or "operative".

within_subj, within_item

(Crossed/mixed, operative only) Whether the effect is within subjects / within items.

Rows are sorted by eta2p in decreasing order.


Partial Eta-Squared for Linear Mixed Models

Description

Calculates partial eta-squared effect sizes for fixed effects in linear mixed models with crossed, nested, or mixed (crossed-and-nested) random effects.

Usage

eta2p(
  model,
  effect,
  data,
  design = c("crossed", "nested", "mixed"),
  subj_var = NULL,
  item_var = NULL,
  cross_vars = NULL,
  nest_vars = NULL,
  effect_level = NULL,
  var_x = NULL,
  operative = FALSE,
  verbose = TRUE
)

Arguments

model

A fitted model object from lme4::lmer().

effect

Character string specifying the fixed effect to analyze. Must match a name in fixef(model).

data

Data frame used to fit the model.

design

Character string: "crossed", "nested", or "mixed". Use "mixed" when the model contains both crossed and nested random effects (e.g., photos nested within models, but both crossed with participants).

subj_var

Character string specifying the subject/participant grouping variable. Retained for backward compatibility; prefer cross_vars.

item_var

Character string specifying the item/stimulus grouping variable. Retained for backward compatibility; prefer cross_vars.

cross_vars

Character vector of grouping variable names that are crossed with each other and with the nested hierarchy (e.g., c("participant") or c("participant", "rater")). Supersedes subj_var and item_var when provided.

nest_vars

Character vector of nesting variables ordered from lowest to highest level (e.g., c("photo", "model") when photos are nested within models). Required for design = "nested" or design = "mixed".

effect_level

Character string specifying the level at which the effect varies (e.g., "L1", "L2"). If NULL, detected automatically from nest_vars.

var_x

Optional numeric. Pre-computed variance of the predictor (or interaction product). If supplied, overrides the internal var() calculation from data. Useful when raw data are unavailable but the predictor variance is known (e.g., from design: a +/-1 binary predictor has var_x = 1).

operative

Logical. If TRUE, calculates operative effect size (excludes variance components that do not contribute to the SE of the effect). Default is FALSE.

verbose

Logical. If TRUE, prints detailed results. Default is TRUE.

Details

Variance decomposition

The function implements a variance decomposition approach for computing partial eta-squared in mixed models. Random slope variances are translated to the outcome scale using:

\sigma^2_{\text{slope}}(Y) = \sigma^2_b \times \sigma^2_X

For interaction effects, \sigma^2_X is computed as the variance of the actual product term, correctly accounting for centering, scaling, and predictor correlation. The var_x argument allows bypassing this computation when the variance is known a priori.

General vs. operative effect sizes

For general effect sizes (default), all variance components appear in the denominator. For operative effect sizes (operative = TRUE), only components that contribute to the standard error of the effect are included. In mixed designs, each grouping factor (both crossed and nested) is independently classified as "within" or "between" the focal effect; between-subjects intercept variances are excluded from the operative denominator.

Mixed designs

Use design = "mixed" when the model contains both crossed and nested random effects simultaneously. A canonical example is participants viewing multiple photos of each model (stimulus): photos are nested within models, but both levels are crossed with participants.

The corresponding lme4 model and eta2p call would be:

fit <- lmer(y ~ x + (1 | participant) + (1 | model) + (1 | photo:model),
            data = dat)
eta2p(fit, "x", dat,
      design     = "mixed",
      cross_vars = "participant",
      nest_vars  = c("photo", "model"))

Residual variance is attributed to the crossed side and counted exactly once; the nested calculator's residual is subtracted to prevent double-counting.

Crossed designs

Supports any number of grouping factors via cross_vars. The two-argument form (subj_var + item_var) is retained for backward compatibility and is equivalent to cross_vars = c(subj_var, item_var).

Value

An object of class "eta2p_lmm" containing:

eta2p

Partial eta-squared value.

variance_effect

Variance explained by the effect.

variance_error

Error variance (denominator).

effect

Name of the effect.

design

Design type: "crossed", "nested", or "mixed".

operative

Whether operative effect size was calculated.

variance_components

List of individual variance components. For "mixed" designs this is a list with $crossed and $nested sub-lists.

within_between

(Mixed/crossed designs) Named list or vector classifying each grouping factor as "within" or "between" with respect to the focal effect. Only populated when operative = TRUE.

cross_vars

(Crossed/mixed designs) Crossed grouping variable names.

nest_vars

(Nested/mixed designs) Nested grouping variable names.

n_per_factor

(Crossed designs) Number of units per crossed factor.

n_cross

(Mixed designs) Number of units per crossed factor.

n_nested

(Mixed designs) Number of units per nested factor.

n_levels

(Nested designs) Number of units per nested level.

effect_level

(Nested/mixed designs) Detected or supplied effect level.

References

Correll, J., Mellinger, C., McClelland, G. H., & Judd, C. M. (2020). Avoid Cohen's 'Small', 'Medium', and 'Large' for Power Analysis. Trends in Cognitive Sciences, 24(3), 200–207. doi:10.1016/j.tics.2019.12.009

Correll, J., Mellinger, C., & Pedersen, E. J. (2022). Flexible approaches for estimating partial eta squared in mixed-effects models with crossed random factors. Behavior Research Methods, 54, 1626–1642. doi:10.3758/s13428-021-01687-2

Rights, J. D., & Sterba, S. K. (2019). Quantifying explained variance in multilevel models: An integrative framework for defining R-squared measures. Psychological Methods, 24(3), 309–338. doi:10.1037/met0000184

Examples


library(lme4)

# --- Two crossed factors (backward-compatible call) ---
set.seed(42)
crossed_data <- data.frame(
  y         = rnorm(120),
  condition = rep(c(-0.5, 0.5), 60),
  subject   = factor(rep(1:20, each = 6)),
  item      = factor(rep(1:6, 20))
)
model_c <- lmer(y ~ condition + (1 | subject) + (1 | item),
                data = crossed_data)
eta2p(model_c, "condition", crossed_data,
      design   = "crossed",
      subj_var = "subject",
      item_var = "item")

# --- Three crossed factors using cross_vars ---
set.seed(42)
three_way_data <- data.frame(
  y         = rnorm(180),
  condition = rep(c(-0.5, 0.5), 90),
  subject   = factor(rep(1:20, each = 9)),
  item      = factor(rep(rep(1:6, each = 3), 10)),
  rater     = factor(rep(1:3, 60))
)
model_3 <- lmer(y ~ condition +
                  (1 | subject) + (1 | item) + (1 | rater),
                data = three_way_data)
eta2p(model_3, "condition", three_way_data,
      design     = "crossed",
      cross_vars = c("subject", "item", "rater"))

# --- Mixed design: photos nested within models, crossed with participants ---
# Participants each view multiple photos of multiple models.
# Photos are nested within models (each photo belongs to one model),
# but both levels are crossed with participants.
set.seed(42)
n_subj  <- 30; n_model <- 10; n_photo <- 3
mixed_data <- expand.grid(
  participant = factor(seq_len(n_subj)),
  photo_id    = factor(seq_len(n_model * n_photo))
)
mixed_data$model_id <- factor(
  rep(seq_len(n_model), each = n_photo)[as.integer(mixed_data$photo_id)]
)
mixed_data$x <- rnorm(nrow(mixed_data))
mixed_data$y <- rnorm(nrow(mixed_data))

model_m <- lmer(y ~ x +
                  (1 | participant) +
                  (1 | model_id) +
                  (1 | photo_id:model_id),
                data = mixed_data)
eta2p(model_m, "x", mixed_data,
      design     = "mixed",
      cross_vars = "participant",
      nest_vars  = c("photo_id", "model_id"))

# --- Supply predictor variance directly (var_x) ---
eta2p(model_c, "condition", crossed_data,
      design     = "crossed",
      cross_vars = c("subject", "item"),
      var_x      = 1)   # +/-1 binary predictor: var = 1 by design