Skip to contents

Post-hoc normal-model shrinkage helper that augments an mfrm_fit with descriptive empirical-Bayes adjustments for each non-person facet. The shrinkage variance \(\hat{\tau}^2\) is estimated by method of moments from the facet-level point estimates and their standard errors: $$\hat{\tau}^2 = \max\!\left(0, \frac{1}{K}\sum_{j=1}^{K}\hat{\delta}_j^{2} - \overline{\mathrm{SE}^2}\right),$$ where zero is the chosen shrinkage target and the moment is calculated on complete finite estimate/positive-SE pairs. A sum-to-zero identification constraint does not establish a known population mean or independent errors. The shrinkage factor is \(B_j = \mathrm{SE}_j^2 / (\hat{\tau}^2 + \mathrm{SE}_j^2)\), with \(\hat{\delta}_j^{EB} = (1-B_j)\hat{\delta}_j\) and \(\mathrm{ShrunkSE}_j = \sqrt{(1-B_j)\mathrm{SE}_j^2}\).

Usage

apply_empirical_bayes_shrinkage(
  fit,
  facet_prior_sd = NULL,
  shrink_person = FALSE
)

Arguments

fit

An mfrm_fit from fit_mfrm() with a non-empty facets$others table.

facet_prior_sd

Optional numeric scalar. When supplied, the shrinkage variance is fixed at facet_prior_sd^2 instead of being estimated from the data. Its square must be representable, and positive when the supplied SD is positive. Useful when a prior is elicited from expert knowledge or a previous fit.

shrink_person

Logical. When TRUE, the same empirical-Bayes adjustment is also applied to ordinary-JML Person estimates with available sampling SEs. Default FALSE. Other estimators are refused: MML EAP estimates already use a population prior, and their posterior SDs are not sampling SEs for a second normal-model update.

Value

The same mfrm_fit, with augmented columns and a new shrinkage_report list entry, and with fit$config$facet_shrinkage set to "empirical_bayes".

Details

ShrunkSE is a plug-in normal-model quantity conditional on the selected prior variance. It omits uncertainty in that variance, cross-level covariance and the fitted identification/anchor constraints. It is neither a calibrated SE nor a guaranteed lower bound. Unequal shrinkage can break the original sum-to-zero constraint. Original estimates, anchors and predictions are unchanged; this helper does not refit a hierarchical MFRM. The normal-normal formula is exact for an independent Gaussian observation with a known Gaussian prior variance. Applying it to jointly calibrated MFRM estimates is a descriptive approximation; a James-Stein improvement in risk is not established for this adjustment.

A zero estimated prior variance fully pools eligible estimates at zero and gives zero plug-in SE; this does not establish perfect precision. Optional plot whiskers are descriptive normal bands. Their legacy CI column names do not confer confidence-interval coverage; SupportsFormalInference is false. Invalid estimate/SE pairs retain their original values with unavailable shrinkage factors. With fewer than three valid pairs no shrinkage is applied. Unrepresentable moment variances also leave the original values unchanged, with unavailable factors and an explanatory Note in the report.

The report records complete-pair counts and mean shrinkage over those pairs. EffectiveDF sums retained weights over eligible levels, conditional on the chosen prior variance; it is not model degrees of freedom for testing or IC. Reapply this helper to existing fits to refresh old reports; no MFRM refit is needed. Regenerate previously saved plots and exports as well. Updated reports carry CalculationVersion = 2: positive prior variances no longer produce zero plug-in SE merely because a shrinkage factor rounded to one. Reapplication replaces the previous adjustment; shrink_person = FALSE removes any previous Person shrinkage columns. The original fitting inputs remain recorded separately from the latest post-fit shrinkage settings. build_mfrm_replay_script() replays the adjustment after fitting, preserving whether diagnostic SEs were attached by fit_mfrm(). Manually edited SEs or other table edits require their own reproducible editing steps.

Typical workflow

  1. Fit the model as usual with fit_mfrm().

  2. Call apply_empirical_bayes_shrinkage(fit) when small-N facets are present and zero-centered pooling is substantively defensible (see facet_small_sample_review()); small counts alone do not require it.

  3. Report both the original and shrunk estimates in the manuscript, citing Efron & Morris (1973). build_apa_outputs() will add the sentence automatically when fit$config$facet_shrinkage is set.

References

Efron, B., & Morris, C. (1973). Combining possibly related estimation problems. Journal of the Royal Statistical Society: Series B, 35(3), 379-402.

Efron, B. (2021). Empirical Bayes: Concepts and methods (Technical report). Department of Statistics, Stanford University. https://efron.ckirby.su.domains/papers/2021EB-concepts-methods.pdf

Morris, C. N. (1983). Parametric empirical Bayes inference: Theory and applications. Journal of the American Statistical Association, 78(381), 47-55.

See also

fit_mfrm() (which accepts facet_shrinkage directly), facet_small_sample_review(), compute_facet_icc().

Examples

# Saved synthetic JML/RSM analysis of example_core.
# For your own data, fit a model first; see ?fit_mfrm.
example_fit <- readRDS(system.file("examples", "core-jml.rds", package = "mfrmr"))
fit <- example_fit$fit
fit_eb <- apply_empirical_bayes_shrinkage(fit)
fit_eb$shrinkage_report
#>       Facet NLevels NLevelsUsed       Tau2     MeanSE2 MeanShrinkage
#> 1     Rater       4           4 0.06402776 0.009499649     0.1291985
#> 2 Criterion       4           4 0.05258949 0.009500118     0.1530052
#>   EffectiveDF          Method PriorSource Note SupportsFormalInference
#> 1    3.483206 empirical_bayes   empirical <NA>                   FALSE
#> 2    3.387979 empirical_bayes   empirical <NA>                   FALSE
#>                                                                                                                                                             Interpretation
#> 1 Descriptive zero-centered adjustment; plug-in SEs/bands omit prior-variance uncertainty and cross-level covariance. Zero SE after full pooling is not perfect precision.
#> 2 Descriptive zero-centered adjustment; plug-in SEs/bands omit prior-variance uncertainty and cross-level covariance. Zero SE after full pooling is not perfect precision.
#>   CalculationVersion
#> 1                  2
#> 2                  2
# Look for:
# - `Tau2` is the estimated between-level prior variance per facet.
#   `Tau2 = 0` fully pools eligible estimates at zero
#   (`MeanShrinkage = 1`). Zero plug-in SE is not perfect precision.
# - `MeanShrinkage` near 0 = little movement, near 1 = heavy pooling
#   toward the chosen zero target; inspect the SEs and prior variance.
# - `EffectiveDF` sums retained weights over eligible levels, conditional
#   on the chosen prior variance; it is not degrees of freedom for testing.
head(fit_eb$facets$others[, c("Facet", "Level", "Estimate",
                               "ShrunkEstimate", "ShrinkageFactor")])
#>       Facet    Level   Estimate ShrunkEstimate ShrinkageFactor
#> 1     Rater      R01 -0.1957463     -0.1705317       0.1288124
#> 2     Rater      R02 -0.3287812     -0.2861288       0.1297287
#> 3     Rater      R03  0.1910898      0.1665008       0.1286778
#> 4     Rater      R04  0.3334376      0.2902324       0.1295752
#> 5 Criterion Accuracy  0.2487265      0.2106950       0.1529051
#> 6 Criterion  Content -0.4150443     -0.3508124       0.1547591
# Look for: rows where `ShrinkageFactor` is large (close to 1) had
#   their estimates pulled most strongly toward the facet mean (0).