The hardware and bandwidth for this mirror is donated by METANET, the Webhosting and Full Service-Cloud Provider.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]metanet.ch.

Migrating from FACETS to mfrmr

This vignette walks FACETS users through the closest mfrmr workflow: preparing data, fitting an RSM/PCM many-facet Rasch-family model with FACETS-oriented settings, generating related diagnostic and reporting tables, and reviewing the output-contract boundary between the two systems. Bounded GPCM can be fit in mfrmr, but its slope-aware score semantics are intentionally outside the score-side FACETS output-contract route.

The software reference target for this migration boundary is FACETS 64-bit 4.5.1 (July 2026). A cited manual may retain its published 4.5.0 edition; software version and documentation edition are recorded separately. The coverage described here is not an external numerical-parity result.

Mental model

The two stacks share the same psychometric framework but differ in operating model.

Before treating a legacy workflow as covered, inspect the public coverage boundary:

facets_feature_coverage()
facets_feature_coverage("not_implemented")

This matrix describes the availability of package-native output surfaces. implemented does not by itself mean that the two programs use the same estimand, conditioning, extreme-score rule, degrees of freedom, or numerical contract.

Concept FACETS (Linacre 2026) mfrmr
Input Specification file plus data file data.frame in long format
Estimation JMLE by default MML by default; JML is the closest estimation route for a JMLE-oriented comparison
Fit-statistic basis Residuals at JMLE estimates Residuals at EAP person measures under MML (shrunken toward the mean); refit with method = "JML" for a JMLE-style residual basis
Models Multiple model statements, rating scales, partial credit, and other response families can coexist One response-model family per fit: RSM, PCM, or bounded GPCM
Output Tables 0-30 plus graphic files Returned R objects with summary() and plot() methods
Anchoring Element/group anchors, rating-scale calibration, and reusable starting values Element and group anchors; no general threshold/scale anchors or fixed-calibration starting-value bundle
Repeated cells Multiple observations may be represented within a design cell Exact Person-by-facet duplicates are retained but force Data review; distinguish legitimate repeats with an event/occasion facet
Bias / interaction Table 14 estimate_bias() and bias_interaction_report()
Wright map / variable map Graphic variable-map output plot(fit, type = "wright") and plot_wright_unified()
Fair average Table 7 fair-M average fair_average_table()
Reproducibility Specification, input data, FACETS version, and recorded run environment/settings build_mfrm_manifest() plus build_mfrm_replay_script()

A one-shot legacy-compatible call

If the goal is to translate a FACETS-style script with minimal R-side plumbing, use run_mfrm_facets() (alias mfrmRFacets()):

library(mfrmr)
data("mfrmr_example_operational", package = "mfrmr")

run <- run_mfrm_facets(
  data = mfrmr_example_operational,
  person = "Person",
  facets = c("Rater", "Criterion"),
  score = "Score",
  model = "RSM",
  method = "JML"
)

names(run)

The wrapper returns the same fit_mfrm() and diagnose_mfrm() objects that a step-by-step pipeline produces, plus the iteration log, fair-average table, and rating-scale table:

jml_status <- summary(run$fit, profile = "fit", detail = "brief")
jml_status$overview[, c(
  "Model", "Method", "Converged", "InferenceReady",
  "ConvergenceSeverity"
)]
jml_status$readiness
head(run$fair_average)

method = "JML" is shown here for a JMLE-oriented migration comparison. Do not infer readiness from Converged alone: require InferenceReady = TRUE for the numerical gate and review the terminal-gradient guidance when severity is "review" or "fail". Numerical readiness does not override a Data, Design, or Stability hold; use the readiness table before interpreting or reporting the fit. For new analysis scripts, prefer fit_mfrm(method = "MML") directly. MML integrates over the person distribution under an N(0, 1) prior and exposes per-person posterior SEs that JML cannot produce.

Translating the specification file

The mapping below covers the most common FACETS specification keywords.

FACETS and labels

Facets = 3
Models = ?,?,?,R5
Labels =
  1, Examinee
    1 = P01
    ...
  2, Rater
    1 = R1
    ...
  3, Criterion
    1 = Content
    ...

translates to:

fit_mfrm(
  data = examinee_long,
  person = "Examinee",
  facets = c("Rater", "Criterion"),
  score = "Score",
  rating_min = 1,
  rating_max = 5,
  model = "RSM"
)

Models = ?,?,?,R5 becomes model = "RSM" and the R5 rating-scale declaration becomes rating_min = 1, rating_max = 5. For a partial-credit specification, pass model = "PCM" and identify the facet that carries the step thresholds with step_facet = "Rater" (or the appropriate facet name).

Anchoring

A FACETS D = 2, A = block:

D = 2
A = 1, 0.0
    2, 0.5

becomes an anchors data frame:

anchors <- data.frame(
  facet = "Rater",
  level = c("R1", "R2"),
  estimate = c(0.0, 0.5),
  stringsAsFactors = FALSE
)
fit <- fit_mfrm(..., anchors = anchors)

review_mfrm_anchors() validates and reports on the anchor block before the fit runs, surfacing connectivity, overlap, and minimum-sample issues.

Bias and interaction

For FACETS Table 14 bias output between Rater and Criterion, the closest mfrmr screening route is:

diag <- diagnose_mfrm(fit)
bias <- estimate_bias(fit, diag,
                      facet_a = "Rater", facet_b = "Criterion")
summary(bias)

estimate_all_bias() enumerates every non-person facet pair in one call.

Wright map / variable map

For a shared-logit visual display of persons, facet levels, and step thresholds, first create the FACETS-organized summary and retain its result object:

review <- summary(fit, profile = "facets", detail = "brief")
res <- review$results

# Primary final-scale figure: all locations and available facet uncertainty.
plot(res, type = "wright", renderer = "native", show_ci = TRUE,
     top_n = Inf, preset = "publication")

plot_wright_unified() is the corresponding explicit helper when the Wright map is the main figure. For readers who expect the FACETS Table 6-style asterisk ruler and horizontal, rubric-labelled category transitions, define one label for every retained original score:

rubric_labels <- setNames(
  your_rubric_labels,
  fit$prep$score_map$OriginalScore
)
plot(res, type = "wright", renderer = "facets", show_ci = FALSE,
     category_labels = rubric_labels, preset = "publication")

show_ci = FALSE is the closest FACETS-style visual grammar. Setting show_ci = TRUE deliberately creates a hybrid display: the ruler is FACETS-style, but the intervals are mfrmr uncertainty estimates. Neither renderer implies that FACETS performed the estimation or that the two programs are numerically equivalent.

For the Bond-and-Fox-style follow-up requested by many FACETS users, put Infit on the horizontal axis and the measure on the vertical axis. Person rows remain opt-in:

plot(res, type = "fit_pathway", fit_stat = "Infit",
     include_person = TRUE, top_n_person = 12,
     person_labels = "none", facet_labels = "flagged")

Use draw = FALSE or plot_data(fit, type = "wright") when you need the underlying coordinates for a custom ggplot2, base-R, or Quarto graphic.

Fit df and ZSTD review

FACETS users often compare Infit/Outfit MnSq together with ZStd columns. In mfrmr, treat MnSq as the primary fit statistic and use the df/ZSTD columns to explain how the same MnSq values were standardized. The direct review path is:

diag <- diagnose_mfrm(fit, residual_pca = "none", fit_df_method = "both")
fm <- fit_measures_table(fit, diagnostics = diag,
                         facet = "Rater", fit_df_method = "both")

fm$facets_table
fm$df_sensitive
plot(fm, type = "df_sensitivity")

df_sensitivity reports the engine-vs-FACETS-style df comparison row by row; df_sensitive keeps only rows where the df convention changes the |ZSTD| flag or materially changes the ZSTD interpretation. The same status taxonomy is used by facets_fit_review(), so a table-oriented review and an external FACETS comparison use the same language.

Group anchoring and DFF

FACETS D = ..., G = group-anchor blocks for differential facet functioning translate to the group_anchors argument and the analyze_dff() follow-up:

group_anchors <- data.frame(
  facet = "Criterion",
  level = "Content",
  group = c("Native", "Non-native"),
  estimate = c(0.0, 0.0),
  stringsAsFactors = FALSE
)
fit_g <- fit_mfrm(..., group_anchors = group_anchors)
dff <- analyze_dff(fit_g, diag, facet = "Criterion",
                   group = "FirstLanguage", method = "refit")

Reviewing output contracts and fit tables

When migrating an existing study, facets_output_contract_review() checks whether the package-generated report components satisfy the FACETS-style output contract encoded in the package:

contract_review <- facets_output_contract_review(
  fit,
  diagnostics = diag,
  branch = "facets"
)
summary(contract_review)
contract_review$missing_preview
contract_review$metric_checks

The resulting object reviews column coverage and package-native metric checks. It is not a claim that mfrmr has reproduced FACETS estimates numerically. For external numerical comparison, use an exported FACETS fit table and facets_fit_review().

When that comparison involves an MML fit, remember that mfrmr evaluates residual-based fit statistics at shrunken EAP person measures while FACETS uses JMLE estimates, so MnSq differences can reflect the residual basis rather than a fit-computation difference; refit with method = "JML" before attributing such gaps. See facets_fit_df_guide() for this boundary and for the separate df/ZSTD standardization conventions.

If you already have a FACETS fit table on disk, read it first and then run the fit review. This does not run FACETS; it consumes an exported or otherwise harmonized table.

facets_fit <- read_facets_fit_table(
  "score.2.txt",
  facet_map = c("1" = "Person", "2" = "Rater", "3" = "Criterion")
)
review <- facets_fit_review(
  fit,
  diagnostics = diag,
  facets_fit = facets_fit,
  external_zstd_tolerance = 0.05
)

review$df_sensitivity
review$df_sensitive
review$external_table_quality
review$external_comparison
plot(review, type = "df_sensitivity")

Use external_comparison for the supplied FACETS table and df_sensitivity for the engine-vs-FACETS-style df convention check. This separation keeps external numerical differences distinct from ZSTD differences caused by df standardization. external_table_quality is the first place to look if the FACETS export only contains ZStd and T.Count columns, or if duplicate Facet x Level rows were supplied.

Producing FACETS-style output files

For traceability or downstream tools that expect FACETS output files, facets_output_file_bundle() writes a parallel set of fixed-width or CSV exports:

files <- facets_output_file_bundle(
  fit,
  diagnostics = diag,
  out_dir = tempdir(),
  include = c("graph", "score")
)

For RSM and PCM the score-side helpers are available. Under bounded GPCM the score-side bundle is intentionally restricted; see ?gpcm_capability_matrix and the mfrmr-gpcm-scope vignette for the documented limitation.

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.