Re-estimates a fitted many-facet model on new data while holding selected
facet parameters fixed at the values from a previous (baseline) calibration.
This transfers baseline coordinates into a new fit through direct equality
constraints. Common-scale interpretation is conditional on a defensible
baseline and invariant cross-run element identity.
For GPCM, treat this as direct exploratory anchor/drift support
rather than as the package's formal linking-synthesis route.
Usage
anchor_to_baseline(
new_data,
baseline_fit,
person,
facets,
score,
anchor_facets = NULL,
include_person = FALSE,
weight = NULL,
model = NULL,
method = NULL,
anchor_policy = "warn",
mml_integration = NULL,
...
)
# S3 method for class 'mfrm_anchored_fit'
print(x, ...)
# S3 method for class 'mfrm_anchored_fit'
summary(object, ...)
# S3 method for class 'summary.mfrm_anchored_fit'
print(x, ...)Arguments
- new_data
Data frame in long format (one row per rating).
- baseline_fit
An inference-ready
mfrm_fitobject from a previous calibration under the current readiness contract.- person
Character column name for person/examinee.
- facets
Character vector of facet column names.
- score
Character column name for the rating score.
- anchor_facets
Character vector of facets to anchor (default: all non-Person facets).
- include_person
If
TRUE, also anchor person estimates. Use only when the same persons are intentionally constrained across runs.- weight
Optional character column name for observation weights.
- model
Scale model override; defaults to baseline model.
- method
Estimation method override; defaults to baseline method.
- anchor_policy
How to handle anchor issues:
"warn","error","silent".- mml_integration
MML integration mode passed to
fit_mfrm().NULLinherits the baseline fit's mode for MML; JML uses"fixed".- ...
For
anchor_to_baseline(), additional arguments passed tofit_mfrm(). Ignored by the S3 print and summary methods on this page.- x
An
mfrm_anchored_fitobject.- object
An
mfrm_anchored_fitobject (forsummary).
Value
Object of class mfrm_anchored_fit with components:
- fit
The anchored
mfrm_fitobject.- diagnostics
Output of
diagnose_mfrm()on the anchored fit.- baseline_anchors
Anchor table extracted from the baseline.
- drift
Tibble of element-level drift statistics.
Details
This function automates the baseline-anchored calibration workflow:
Extracts anchor values from the baseline fit using
make_anchor_table().Re-estimates the model on
new_datawith those anchors fixed viafit_mfrm(..., anchors = anchor_table).Runs
diagnose_mfrm()on the anchored fit.Computes element-level differences (new estimate minus baseline estimate) for every common element.
The helper refuses a baseline unless its current readiness record has
InferenceReady = TRUE. Also confirm compatible model, score coding,
orientation, and population conventions, and document that anchor labels
denote the same elements with invariant meaning. The function checks object
shape and receiving-data anchor compatibility, but does not establish those
substantive conditions. Fixing parameters can identify coordinates; it does
not create observed common-rating links.
The model and method arguments default to the baseline fit's settings
so the calibration framework remains consistent. Elements present in the
anchor table but absent from the new data are handled according to
anchor_policy: "warn" (default) emits a message, "error" stops
execution, and "silent" ignores silently.
The returned drift table is best interpreted as an anchored consistency
check. When a facet is fixed through anchor_facets, those anchored levels
are constrained in the new run, so their reported differences are not an
independent drift analysis. For genuine cross-wave drift monitoring, fit the
waves separately and use detect_anchor_drift() on the resulting fits.
Element-level differences are calculated for every element that appears in
both the baseline and the new calibration:
$$\Delta_e = \hat{\delta}_{e,\text{new}} - \hat{\delta}_{e,\text{base}}$$
An element is flagged when \(|\Delta_e| > 0.5\) logits or
\(|\Delta_e / SE_{\Delta_e}| > 2.0\), where
\(SE_{\Delta_e} = \sqrt{SE_{\mathrm{base}}^2 + SE_{\mathrm{new}}^2}\).
SE_Diff is a plug-in independence calculation. It does not propagate
baseline-anchor uncertainty or cross-fit covariance, and anchored estimates
in the new fit are constrained rather than independently re-estimated.
Consequently, Drift_SE_Ratio and Flag are descriptive consistency
screens, not formal z tests or calibrated error-rate decisions.
Which function should I use?
Use
anchor_to_baseline()when you have one new dataset and want to place it directly on a baseline scale.Use
detect_anchor_drift()when you already have multiple fitted waves and want to compare their stability.Use
build_equating_chain()when you need cumulative offsets across an ordered series of waves.
Interpreting output
$drift: one row per common element with columnsFacet,Level,Baseline,New,Drift,SE_Baseline,SE_New,SE_Diff,Drift_SE_Ratio, andFlag. Read this as an anchored consistency table. Small absolute differences indicate that the anchored re-fit stayed close to the baseline scale. Flagged rows warrant review, but they are not a substitute for a separate drift study on unanchored common elements.$fit: the full anchoredmfrm_fitobject, usable withdiagnose_mfrm(),measurable_summary_table(), etc.$diagnostics: pre-computed diagnostics for the anchored calibration.$baseline_anchors: the anchor table fed tofit_mfrm(), useful for reviewing which elements were constrained.
Typical workflow
Fit the baseline model:
fit1 <- fit_mfrm(...).Collect new data (e.g., a later administration).
Call
res <- anchor_to_baseline(new_data, fit1, ...).Inspect
summary(res)to confirm the anchored run remains close to the baseline scale.For multi-wave drift monitoring, fit waves separately and pass the fits to
detect_anchor_drift()orbuild_equating_chain().
Examples
# \donttest{
# Deliberately linked teaching waves: both retain the same rater and
# criterion identities from one synthetic calibration design.
toy <- load_mfrmr_data("example_core")
people <- unique(toy$Person)
# Two balanced 12-Person waves retain every Rater and Criterion.
d1 <- toy[toy$Person %in% people[1:12], , drop = FALSE]
d2 <- toy[toy$Person %in% people[13:24], , drop = FALSE]
fit1 <- fit_mfrm(d1, "Person", c("Rater", "Criterion"), "Score",
method = "MML", quad_points = 7, maxit = 30)
res <- anchor_to_baseline(d2, fit1, "Person",
c("Rater", "Criterion"), "Score",
anchor_facets = "Criterion")
summary(res)
#> --- Anchored Fit Summary ---
#> Inference-ready: TRUE
#> Optimizer returned code 0: TRUE | Status: converged
#> Anchors used: 4 | Common elements: 4 | Flagged: 0
#>
#> Drift by facet:
#> Facet N Mean_Drift Max_Drift N_Flagged
#> Criterion 4 0 0 0
head(res$drift[, c("Facet", "Level", "Drift", "Flag")])
#> # A tibble: 4 × 4
#> Facet Level Drift Flag
#> <chr> <chr> <dbl> <lgl>
#> 1 Criterion Accuracy 0 FALSE
#> 2 Criterion Content 0 FALSE
#> 3 Criterion Language 0 FALSE
#> 4 Criterion Organization 0 FALSE
res$baseline_anchors[1:3, ]
#> # A tibble: 3 × 3
#> Facet Level Anchor
#> <chr> <chr> <dbl>
#> 1 Criterion Accuracy 0.210
#> 2 Criterion Content -0.443
#> 3 Criterion Language 0.0979
# }
