This vignette outlines a reproducible workflow for:
For a plot-first companion guide, see the separate
mfrmr-visual-diagnostics vignette.
For speed-sensitive work, a useful pattern is:
method = "JML" or
quad_points = 7diagnose_mfrm(..., residual_pca = "none") for the
first passmfrmr treats MML and JML
differently on purpose.
MML integrates over the person distribution with
Gauss-Hermite quadrature.MML branch optimizes the quadrature-based
marginal log-likelihood directly; it is not an EM implementation.JML is often useful for quick exploratory passes, but
MML remains the preferred route for final estimation and
fixed-calibration follow-up.For RSM and PCM, diagnostics now expose two
distinct evidence paths:
diagnostic_mode = "legacy" keeps the residual/EAP-based
stack.diagnostic_mode = "marginal_fit" adds the strict
latent-integrated screen.diagnostic_mode = "both" is the safest default when you
want to inspect both views side by side.The strict marginal branch is still screening-oriented in the current
release. Use summary(diag)$diagnostic_basis to separate the
legacy residual evidence from the strict marginal evidence rather than
pooling them into one decision.
library(mfrmr)
list_mfrmr_data()
#> [1] "example_core" "example_bias" "study1" "study2"
#> [5] "combined" "study1_itercal" "study2_itercal" "combined_itercal"
data("ej2021_study1", package = "mfrmr")
head(ej2021_study1)
#> Study Person Rater Criterion Score
#> 1 Study1 P001 R08 Global_Impression 4
#> 2 Study1 P001 R08 Linguistic_Realization 3
#> 3 Study1 P001 R08 Task_Fulfillment 3
#> 4 Study1 P001 R10 Global_Impression 4
#> 5 Study1 P001 R10 Linguistic_Realization 3
#> 6 Study1 P001 R10 Task_Fulfillment 2
study1_alt <- load_mfrmr_data("study1")
identical(names(ej2021_study1), names(study1_alt))
#> [1] TRUEWe start with the packaged example_core dataset. It is
intentionally compact, category-complete, and generated from a single
latent trait plus facet main effects so that help-page examples stay
fast without relying on undersized toy data. The same object is also
available via
data("mfrmr_example_core", package = "mfrmr"):
data("mfrmr_example_core", package = "mfrmr")
toy <- mfrmr_example_core
fit_toy <- fit_mfrm(
data = toy,
person = "Person",
facets = c("Rater", "Criterion"),
score = "Score",
method = "JML",
model = "RSM",
maxit = 15
)
#> Warning: Optimizer did not fully converge (code = 1, status = iteration_limit).
#> Optimizer reached the iteration limit before the terminal gradient became small
#> enough for review-only acceptance. Consider increasing maxit (current: 15) or
#> relaxing reltol (current: 1e-06).
diag_toy <- diagnose_mfrm(fit_toy, residual_pca = "none")
summary(fit_toy)$overview
#> # A tibble: 1 × 33
#> Model Method MethodUsed N Persons Facets Categories LogLik AIC BIC
#> <chr> <chr> <chr> <int> <int> <int> <dbl> <dbl> <dbl> <dbl>
#> 1 RSM JML JMLE 768 48 2 4 -822. 1758. 2022.
#> # ℹ 23 more variables: Converged <lgl>, Iterations <int>,
#> # IterationsBasis <chr>, MMLEngineRequested <chr>, MMLEngineUsed <chr>,
#> # MMLEngineDetail <chr>, EMIterations <int>, EMConverged <lgl>,
#> # EMRelativeChange <dbl>, OptimizerMethod <chr>, ConvergenceCode <int>,
#> # ConvergenceBasis <chr>, ConvergenceStatus <chr>, ConvergenceReason <chr>,
#> # ConvergenceSeverity <chr>, ConvergenceMessage <chr>,
#> # ConvergenceDetail <chr>, ReviewableWarning <lgl>, …
summary(diag_toy)$overview
#> # A tibble: 1 × 10
#> Observations Persons Facets Categories Subsets ResidualPCA DiagnosticMode
#> <int> <int> <int> <int> <int> <chr> <chr>
#> 1 768 48 2 4 1 none legacy
#> # ℹ 3 more variables: Method <chr>, PrecisionTier <chr>, MarginalFit <chr>
names(plot(fit_toy, draw = FALSE))
#> [1] "wright_map" "pathway_map"
#> [3] "category_characteristic_curves"t4_toy <- unexpected_response_table(
fit_toy,
diagnostics = diag_toy,
abs_z_min = 1.5,
prob_max = 0.4,
top_n = 10
)
t12_toy <- fair_average_table(fit_toy, diagnostics = diag_toy)
t13_toy <- bias_interaction_report(
estimate_bias(fit_toy, diag_toy,
facet_a = "Rater", facet_b = "Criterion",
max_iter = 2),
top_n = 10
)
class(summary(t4_toy))
#> [1] "summary.mfrm_bundle"
class(summary(t12_toy))
#> [1] "summary.mfrm_bundle"
class(summary(t13_toy))
#> [1] "summary.mfrm_bundle"
names(plot(t4_toy, draw = FALSE))
#> [1] "name" "data"
names(plot(t12_toy, draw = FALSE))
#> [1] "name" "data"
names(plot(t13_toy, draw = FALSE))
#> [1] "name" "data"
chk_toy <- reporting_checklist(fit_toy, diagnostics = diag_toy)
subset(
chk_toy$checklist,
Section == "Visual Displays",
c("Item", "DraftReady", "NextAction")
)
#> Item DraftReady
#> 21 Wright map TRUE
#> 22 QC / facet dashboard TRUE
#> 23 Residual PCA visuals FALSE
#> 24 Connectivity / design-matrix visual TRUE
#> 25 Inter-rater / displacement visuals TRUE
#> 26 Strict marginal visuals FALSE
#> 27 Bias / DIF visuals FALSE
#> 28 Precision / information curves FALSE
#> 29 Fit/category visuals TRUE
#> NextAction
#> 21 Include a Wright map when the manuscript benefits from a shared-scale targeting display.
#> 22 Use the dashboard as a first-pass triage view, then move to the specific follow-up plot behind each flag.
#> 23 Run residual PCA if you want scree/loadings visuals for residual-structure follow-up.
#> 24 Use the design-matrix view to support linkage and comparability claims.
#> 25 Use displacement and inter-rater views to localize QC issues after dashboard screening.
#> 26 For MML reporting runs, call diagnose_mfrm(..., diagnostic_mode = "both") to enable strict marginal follow-up visuals where supported.
#> 27 Run bias or DIF screening before discussing interaction-level visuals.
#> 28 Resolve convergence before using information or precision curves in reporting.
#> 29 Use category curves and fit visuals as local descriptive follow-up after QC screening.For a realistic analysis, we use the packaged Study 1 dataset:
fit <- fit_mfrm(
data = ej2021_study1,
person = "Person",
facets = c("Rater", "Criterion"),
score = "Score",
method = "MML",
model = "RSM",
quad_points = 7
)
diag <- diagnose_mfrm(
fit,
residual_pca = "none"
)
summary(fit)
#> Many-Facet Rasch Model Summary
#> Model: RSM | Method: MML | N: 1842 | Persons: 307 | Facets: 2 | Categories: 4
#> MML engine: direct (requested: direct)
#>
#> Status
#> - Overall status: usable_fit
#> - Convergence: converged (severity: pass, sup-norm: 0.374)
#> - Estimation path: RSM / direct
#> - Reporting readiness: ready_for_diagnostics_and_reporting_follow_up
#>
#> Key warnings
#> - No population model was requested; current MML output uses the package's legacy unconditional prior.
#>
#> Next actions
#> - Run `diagnose_mfrm(fit, diagnostic_mode = "both")` for element-level fit review.
#> - Use `plot(fit, type = "wright", preset = "publication")` for targeting and scale review.
#> - After diagnostics, use `reporting_checklist(fit, diagnostics = diagnostics)` for reporting readiness.
#>
#> Fit overview
#> LogLik: -2102.737 | AIC: 4249.475 | BIC: 4370.884
#> Converged: Yes | Status: converged | Basis: optimizer_gradient | Fn evals: 80 | Gr evals: 23
#> Terminal gradient: sup-norm = 0.374 | RMS = 0.15 | Review tol = 0
#> Optimization note: Optimizer returned convergence code 0.
#>
#> Population basis
#> PopulationModel PosteriorBasis Formula PersonRows DesignColumns
#> FALSE legacy_mml <NA> NA NA
#> CodingVariables ContrastVariables Policy ResidualVariance OmittedPersons
#> <NA> NA 0
#> OmittedRows
#> 0
#>
#> Facet overview
#> Facet Levels MeanEstimate SDEstimate MinEstimate MaxEstimate Span
#> Criterion 3 0 0.692 -0.799 0.430 1.229
#> Rater 18 0 0.665 -0.946 1.619 2.565
#>
#> Person measure distribution
#> Persons Mean SD Median Min Max Span MeanPosteriorSD
#> 307 0.414 0.812 0.439 -1.451 2.384 3.834 0.482
#>
#> Step parameter summary
#> Steps Min Max Span Monotonic
#> 3 -1.092 0.957 2.05 TRUE
#>
#> Estimation settings
#> StepFacet SlopeFacet NoncenterFacet WeightColumn QuadPoints RatingMin
#> <NA> <NA> Person <NA> 7 1
#> RatingMax DummyFacets PositiveFacets UnusedScoreCategories
#> 4
#> UnusedScoreCategoryCount UnusedScoreCategoryType
#> 0 none
#>
#> Most extreme facet levels (|estimate|)
#> Facet Level Estimate
#> Rater R13 1.619
#> Rater R08 -0.946
#> Rater R09 -0.918
#> Rater R06 0.886
#> Criterion Global_Impression -0.799
#>
#> Highest person measures
#> Person Estimate SD
#> P157 2.384 0.466
#> P239 2.346 0.543
#> P135 2.263 0.470
#> P018 2.121 0.612
#> P209 2.014 0.644
#>
#> Lowest person measures
#> Person Estimate SD
#> P136 -1.451 0.555
#> P173 -1.399 0.526
#> P159 -1.349 0.579
#> P048 -1.330 0.466
#> P089 -1.274 0.395
#>
#> Paper reporting map
#> Area CoveredHere
#> Model identification / convergence yes
#> Data structure / missingness no
#> Reliability / fit / residual PCA no
#> Category functioning partial
#> Bias / DIF / interaction checks no
#> Draft reporting / checklist no
#> CompanionOutput
#> summary(fit)
#> summary(describe_mfrm_data(...))
#> summary(diagnose_mfrm(fit))
#> rating_scale_table() / category_structure_report() / category_curves_report()
#> summary(estimate_bias(...)) / analyze_dff() / related bundle summaries
#> reporting_checklist() / summary(build_apa_outputs(...))
#>
#> Notes
#> - No population model was requested; current MML output uses the package's legacy unconditional prior.
summary(diag)
#> Many-Facet Rasch Diagnostics Summary
#> Observations: 1842 | Persons: 307 | Facets: 2 | Categories: 4 | Subsets: 1
#> Residual PCA mode: none
#> Method: MML | Precision tier: model_based
#> Diagnostic mode: legacy | Strict marginal fit: not_available
#>
#> Status
#> - Overall status: follow_up_needed
#> - Diagnostic path: legacy
#> - Strict marginal fit: not_requested
#> - Precision tier: model_based
#> - Primary screen: Legacy residual diagnostics only; no strict marginal screen was requested.
#>
#> Key warnings
#> - Unexpected responses flagged: 100.
#> - Flagged displacement levels: 40.
#>
#> Next actions
#> - Inspect `diagnostic_basis` before comparing legacy residual evidence with strict marginal evidence.
#> - Use `unexpected_response_table()` / `plot_unexpected()` and `displacement_table()` / `plot_displacement()` for case-level follow-up.
#>
#> Overall fit
#> Infit Outfit InfitZSTD OutfitZSTD DF_Infit DF_Outfit
#> 0.811 0.786 -4.643 -7.029 1059.444 1842
#>
#> Diagnostic basis guide
#> DiagnosticPath Component
#> legacy_residual_fit element_residual_fit
#> strict_marginal_fit first_order_category_counts
#> strict_pairwise_local_dependence pairwise_local_dependence
#> posterior_predictive_follow_up posterior_predictive_follow_up
#> Status Basis
#> computed plugin_residuals_and_eap_tables
#> not_requested latent_integrated_first_order_counts
#> not_requested latent_integrated_second_order_agreement
#> planned_not_implemented posterior_predictive_replication
#> PrimaryStatistics
#> Infit / Outfit / ZSTD / PTMEA / residual QC bundles
#> category residuals / standardized residuals / RMSD
#> exact and adjacent agreement residuals
#> replicated-data discrepancy checks
#> ReportingUse
#> legacy_compatibility_screen
#> screening_only
#> screening_only
#> screening_only
#> InterpretationNote
#> Legacy fit statistics use plug-in residual machinery and should not be interpreted as latent-integrated marginal evidence.
#> Strict marginal fit integrates over the latent distribution and is the preferred strict screen for category-level misfit in the current release.
#> Strict pairwise local-dependence checks are exploratory follow-ups to first-order marginal flags, not standalone inferential tests.
#> Posterior predictive checking is reserved for corroborating strict marginal flags and practical-significance review in a later release.
#>
#> Precision basis
#> Method Converged PrecisionTier SupportsFormalInference HasFallbackSE
#> MML TRUE model_based TRUE FALSE
#> PersonSEBasis NonPersonSEBasis
#> Posterior SD (EAP) Observed information (MML)
#> CIBasis
#> Normal interval from model-based SE
#> ReliabilityBasis
#> Observed variance with model-based and fit-adjusted error bounds
#> HasFitAdjustedSE HasSamplePopulationCoverage
#> TRUE TRUE
#> RecommendedUse
#> Use for primary reporting of SE, CI, and reliability in this package.
#>
#> Facet precision and spread
#> Facet Levels Separation Strata Reliability RealSeparation RealStrata
#> Criterion 3 14.910 20.214 0.996 14.910 20.214
#> Person 307 1.322 2.096 0.636 1.225 1.967
#> Rater 18 3.118 4.490 0.907 3.107 4.476
#> RealReliability MeanInfit MeanOutfit
#> 0.996 0.810 0.786
#> 0.600 0.798 0.786
#> 0.906 0.813 0.786
#>
#> Largest |ZSTD| rows
#> Facet Level Infit Outfit InfitZSTD OutfitZSTD AbsZ
#> Criterion Global_Impression 0.798 0.744 -2.596 -4.922 4.922
#> Rater R08 0.702 0.660 -2.439 -4.107 4.107
#> Criterion Linguistic_Realization 0.802 0.797 -2.918 -3.817 3.817
#> Person P020 0.027 0.026 -2.768 -3.464 3.464
#> Criterion Task_Fulfillment 0.829 0.816 -2.488 -3.422 3.422
#> Rater R10 0.737 0.726 -2.189 -2.939 2.939
#> Person P203 0.041 0.073 -2.497 -2.832 2.832
#> Person P098 2.314 3.361 1.539 2.780 2.780
#> Rater R05 0.744 0.749 -1.923 -2.535 2.535
#> Person P056 0.075 0.125 -1.727 -2.405 2.405
#>
#> Strict marginal fit
#> Available Method Model Basis
#> FALSE MML RSM latent_integrated_first_order_counts
#> Reason
#> Not computed; use `diagnostic_mode = "marginal_fit"` or `"both"`.
#>
#> Paper reporting map
#> Area CoveredHere
#> Overall fit / reliability yes
#> Precision basis / inferential caveats yes
#> Strict marginal fit no
#> Residual PCA / local structure partial
#> Unexpected responses / displacement partial
#> Connectivity / subsets partial
#> Manuscript checklist / export no
#> CompanionOutput
#> summary(diagnostics)
#> summary(diagnostics)
#> diagnose_mfrm(..., diagnostic_mode = "both")
#> analyze_residual_pca() / diagnostics$pca details
#> unexpected_response_table() / displacement_table() / interaction tables
#> subset_connectivity_report() / measurable_summary_table()
#> reporting_checklist() / summary(build_apa_outputs(...))
#>
#> Flag counts
#> Metric Count
#> Unexpected responses 100
#> Flagged displacement levels 40
#> Interaction rows 20
#> Inter-rater pairs 153
#> Marginal fit flagged groups NA
#> Marginal pairwise flagged level pairs NA
#>
#> Notes
#> - Unexpected responses were flagged under current thresholds.
#> - SE/ModelSE, CI, and reliability conventions depend on the estimation path; see diagnostics$approximation_notes for MML-vs-JML details.
#> - Use `diagnostics$reliability` for facet-level separation/reliability. Use `diagnostics$interrater` only for observed agreement across matched rater contexts.If you need dimensionality evidence for a final report, you can add residual PCA after the initial diagnostic pass:
diag_pca <- diagnose_mfrm(
fit,
residual_pca = "both",
pca_max_factors = 6
)
summary(diag_pca)
#> Many-Facet Rasch Diagnostics Summary
#> Observations: 1842 | Persons: 307 | Facets: 2 | Categories: 4 | Subsets: 1
#> Residual PCA mode: both
#> Method: MML | Precision tier: model_based
#> Diagnostic mode: legacy | Strict marginal fit: not_available
#>
#> Status
#> - Overall status: follow_up_needed
#> - Diagnostic path: legacy
#> - Strict marginal fit: not_requested
#> - Precision tier: model_based
#> - Primary screen: Legacy residual diagnostics only; no strict marginal screen was requested.
#>
#> Key warnings
#> - Unexpected responses flagged: 100.
#> - Flagged displacement levels: 40.
#>
#> Next actions
#> - Inspect `diagnostic_basis` before comparing legacy residual evidence with strict marginal evidence.
#> - Use `unexpected_response_table()` / `plot_unexpected()` and `displacement_table()` / `plot_displacement()` for case-level follow-up.
#> - Use `analyze_residual_pca()` if residual structure needs deeper follow-up.
#>
#> Overall fit
#> Infit Outfit InfitZSTD OutfitZSTD DF_Infit DF_Outfit
#> 0.811 0.786 -4.643 -7.029 1059.444 1842
#>
#> Diagnostic basis guide
#> DiagnosticPath Component
#> legacy_residual_fit element_residual_fit
#> strict_marginal_fit first_order_category_counts
#> strict_pairwise_local_dependence pairwise_local_dependence
#> posterior_predictive_follow_up posterior_predictive_follow_up
#> Status Basis
#> computed plugin_residuals_and_eap_tables
#> not_requested latent_integrated_first_order_counts
#> not_requested latent_integrated_second_order_agreement
#> planned_not_implemented posterior_predictive_replication
#> PrimaryStatistics
#> Infit / Outfit / ZSTD / PTMEA / residual QC bundles
#> category residuals / standardized residuals / RMSD
#> exact and adjacent agreement residuals
#> replicated-data discrepancy checks
#> ReportingUse
#> legacy_compatibility_screen
#> screening_only
#> screening_only
#> screening_only
#> InterpretationNote
#> Legacy fit statistics use plug-in residual machinery and should not be interpreted as latent-integrated marginal evidence.
#> Strict marginal fit integrates over the latent distribution and is the preferred strict screen for category-level misfit in the current release.
#> Strict pairwise local-dependence checks are exploratory follow-ups to first-order marginal flags, not standalone inferential tests.
#> Posterior predictive checking is reserved for corroborating strict marginal flags and practical-significance review in a later release.
#>
#> Precision basis
#> Method Converged PrecisionTier SupportsFormalInference HasFallbackSE
#> MML TRUE model_based TRUE FALSE
#> PersonSEBasis NonPersonSEBasis
#> Posterior SD (EAP) Observed information (MML)
#> CIBasis
#> Normal interval from model-based SE
#> ReliabilityBasis
#> Observed variance with model-based and fit-adjusted error bounds
#> HasFitAdjustedSE HasSamplePopulationCoverage
#> TRUE TRUE
#> RecommendedUse
#> Use for primary reporting of SE, CI, and reliability in this package.
#>
#> Facet precision and spread
#> Facet Levels Separation Strata Reliability RealSeparation RealStrata
#> Criterion 3 14.910 20.214 0.996 14.910 20.214
#> Person 307 1.322 2.096 0.636 1.225 1.967
#> Rater 18 3.118 4.490 0.907 3.107 4.476
#> RealReliability MeanInfit MeanOutfit
#> 0.996 0.810 0.786
#> 0.600 0.798 0.786
#> 0.906 0.813 0.786
#>
#> Largest |ZSTD| rows
#> Facet Level Infit Outfit InfitZSTD OutfitZSTD AbsZ
#> Criterion Global_Impression 0.798 0.744 -2.596 -4.922 4.922
#> Rater R08 0.702 0.660 -2.439 -4.107 4.107
#> Criterion Linguistic_Realization 0.802 0.797 -2.918 -3.817 3.817
#> Person P020 0.027 0.026 -2.768 -3.464 3.464
#> Criterion Task_Fulfillment 0.829 0.816 -2.488 -3.422 3.422
#> Rater R10 0.737 0.726 -2.189 -2.939 2.939
#> Person P203 0.041 0.073 -2.497 -2.832 2.832
#> Person P098 2.314 3.361 1.539 2.780 2.780
#> Rater R05 0.744 0.749 -1.923 -2.535 2.535
#> Person P056 0.075 0.125 -1.727 -2.405 2.405
#>
#> Strict marginal fit
#> Available Method Model Basis
#> FALSE MML RSM latent_integrated_first_order_counts
#> Reason
#> Not computed; use `diagnostic_mode = "marginal_fit"` or `"both"`.
#>
#> Paper reporting map
#> Area CoveredHere
#> Overall fit / reliability yes
#> Precision basis / inferential caveats yes
#> Strict marginal fit no
#> Residual PCA / local structure partial
#> Unexpected responses / displacement partial
#> Connectivity / subsets partial
#> Manuscript checklist / export no
#> CompanionOutput
#> summary(diagnostics)
#> summary(diagnostics)
#> diagnose_mfrm(..., diagnostic_mode = "both")
#> analyze_residual_pca() / diagnostics$pca details
#> unexpected_response_table() / displacement_table() / interaction tables
#> subset_connectivity_report() / measurable_summary_table()
#> reporting_checklist() / summary(build_apa_outputs(...))
#>
#> Flag counts
#> Metric Count
#> Unexpected responses 100
#> Flagged displacement levels 40
#> Interaction rows 20
#> Inter-rater pairs 153
#> Marginal fit flagged groups NA
#> Marginal pairwise flagged level pairs NA
#>
#> Notes
#> - Unexpected responses were flagged under current thresholds.
#> - SE/ModelSE, CI, and reliability conventions depend on the estimation path; see diagnostics$approximation_notes for MML-vs-JML details.
#> - Use `diagnostics$reliability` for facet-level separation/reliability. Use `diagnostics$interrater` only for observed agreement across matched rater contexts.For RSM and PCM, the package can now keep
the legacy residual path and the strict marginal path side by side:
fit_rsm_strict <- fit_mfrm(
data = toy,
person = "Person",
facets = c("Rater", "Criterion"),
score = "Score",
method = "MML",
model = "RSM",
quad_points = 7,
maxit = 10
)
#> Warning: Optimizer did not fully converge (code = 1, status = iteration_limit).
#> Optimizer reached the iteration limit before the terminal gradient became small
#> enough for review-only acceptance. Consider increasing maxit (current: 10) or
#> relaxing reltol (current: 1e-06).
diag_rsm_strict <- diagnose_mfrm(
fit_rsm_strict,
diagnostic_mode = "both",
residual_pca = "none"
)
fit_pcm_strict <- fit_mfrm(
data = toy,
person = "Person",
facets = c("Rater", "Criterion"),
score = "Score",
method = "MML",
model = "PCM",
step_facet = "Criterion",
quad_points = 7,
maxit = 10
)
#> Warning: Optimizer did not fully converge (code = 1, status = iteration_limit).
#> Optimizer reached the iteration limit before the terminal gradient became small
#> enough for review-only acceptance. Consider increasing maxit (current: 10) or
#> relaxing reltol (current: 1e-06).
diag_pcm_strict <- diagnose_mfrm(
fit_pcm_strict,
diagnostic_mode = "both",
residual_pca = "none"
)
summary(diag_rsm_strict)$diagnostic_basis[, c("DiagnosticPath", "Status", "Basis")]
#> # A tibble: 4 × 3
#> DiagnosticPath Status Basis
#> <chr> <chr> <chr>
#> 1 legacy_residual_fit computed plugin_residuals_and…
#> 2 strict_marginal_fit computed latent_integrated_fi…
#> 3 strict_pairwise_local_dependence computed latent_integrated_se…
#> 4 posterior_predictive_follow_up planned_not_implemented posterior_predictive…
summary(diag_pcm_strict)$diagnostic_basis[, c("DiagnosticPath", "Status", "Basis")]
#> # A tibble: 4 × 3
#> DiagnosticPath Status Basis
#> <chr> <chr> <chr>
#> 1 legacy_residual_fit computed plugin_residuals_and…
#> 2 strict_marginal_fit computed latent_integrated_fi…
#> 3 strict_pairwise_local_dependence computed latent_integrated_se…
#> 4 posterior_predictive_follow_up planned_not_implemented posterior_predictive…When you want a compact simulation-based screening check for the
strict branch, use evaluate_mfrm_diagnostic_screening() on
a small design:
screen_rsm <- evaluate_mfrm_diagnostic_screening(
design = list(person = 18, rater = 3, criterion = 3, assignment = 3),
reps = 1,
scenarios = c("well_specified", "local_dependence"),
model = "RSM",
maxit = 8,
quad_points = 7,
seed = 123
)
#> Warning: Optimizer did not fully converge (code = 1, status = iteration_limit).
#> Optimizer reached the iteration limit before the terminal gradient became small
#> enough for review-only acceptance. Consider increasing maxit (current: 8) or
#> relaxing reltol (current: 1e-06).
#> Warning: Optimizer did not fully converge (code = 1, status = iteration_limit).
#> Optimizer reached the iteration limit before the terminal gradient became small
#> enough for review-only acceptance. Consider increasing maxit (current: 8) or
#> relaxing reltol (current: 1e-06).
screen_pcm <- evaluate_mfrm_diagnostic_screening(
design = list(person = 18, rater = 3, criterion = 3, assignment = 3),
reps = 1,
scenarios = c("well_specified", "step_structure_misspecification"),
model = "PCM",
maxit = 8,
quad_points = 7,
seed = 123
)
#> Warning: Optimizer did not fully converge (code = 1, status = iteration_limit).
#> Optimizer reached the iteration limit before the terminal gradient became small
#> enough for review-only acceptance. Consider increasing maxit (current: 8) or
#> relaxing reltol (current: 1e-06).
#> Warning: Optimizer did not fully converge (code = 1, status = iteration_limit).
#> Optimizer reached the iteration limit before the terminal gradient became small
#> enough for review-only acceptance. Consider increasing maxit (current: 8) or
#> relaxing reltol (current: 1e-06).
screen_rsm$performance_summary[, c("Scenario", "EvaluationUse", "LegacyAnyFlagRate", "StrictAnyFlagRate")]
#> # A tibble: 2 × 4
#> Scenario EvaluationUse LegacyAnyFlagRate StrictAnyFlagRate
#> <chr> <chr> <dbl> <dbl>
#> 1 local_dependence sensitivity_proxy 0 1
#> 2 well_specified type_I_proxy 1 1
screen_pcm$performance_summary[, c("Scenario", "EvaluationUse", "LegacySensitivityProxy", "StrictSensitivityProxy", "DeltaStrictMinusLegacyFlagRate")]
#> # A tibble: 2 × 5
#> Scenario EvaluationUse LegacySensitivityProxy StrictSensitivityProxy
#> <chr> <chr> <dbl> <dbl>
#> 1 step_structure_mi… sensitivity_… 1 1
#> 2 well_specified type_I_proxy NA NA
#> # ℹ 1 more variable: DeltaStrictMinusLegacyFlagRate <dbl>The same strict branch is now reflected in the reporting router:
chk_rsm_strict <- reporting_checklist(fit_rsm_strict, diagnostics = diag_rsm_strict)
subset(
chk_rsm_strict$checklist,
Section == "Visual Displays" &
Item %in% c("QC / facet dashboard", "Strict marginal visuals", "Precision / information curves"),
c("Item", "Available", "DraftReady", "NextAction")
)
#> Item Available DraftReady
#> 22 QC / facet dashboard TRUE TRUE
#> 26 Strict marginal visuals TRUE FALSE
#> 28 Precision / information curves FALSE FALSE
#> NextAction
#> 22 Use the dashboard as a first-pass triage view, then move to the specific follow-up plot behind each flag.
#> 26 Treat strict marginal plots as exploratory corroboration screens, then corroborate with design review and legacy diagnostics.
#> 28 Resolve convergence before using information or precision curves in reporting.pca <- analyze_residual_pca(diag_pca, mode = "both")
plot_residual_pca(pca, mode = "overall", plot_type = "scree")data("mfrmr_example_bias", package = "mfrmr")
bias_df <- mfrmr_example_bias
fit_bias <- fit_mfrm(
bias_df,
person = "Person",
facets = c("Rater", "Criterion"),
score = "Score",
method = "MML",
model = "RSM",
quad_points = 7
)
diag_bias <- diagnose_mfrm(fit_bias, residual_pca = "none")
bias <- estimate_bias(fit_bias, diag_bias, facet_a = "Rater", facet_b = "Criterion")
fixed <- build_fixed_reports(bias)
apa <- build_apa_outputs(fit_bias, diag_bias, bias_results = bias)
mfrm_threshold_profiles()
#> $profiles
#> $profiles$strict
#> $profiles$strict$n_obs_min
#> [1] 200
#>
#> $profiles$strict$n_person_min
#> [1] 50
#>
#> $profiles$strict$low_cat_min
#> [1] 15
#>
#> $profiles$strict$min_facet_levels
#> [1] 4
#>
#> $profiles$strict$misfit_ratio_warn
#> [1] 0.08
#>
#> $profiles$strict$missing_fit_ratio_warn
#> [1] 0.15
#>
#> $profiles$strict$zstd2_ratio_warn
#> [1] 0.08
#>
#> $profiles$strict$zstd3_ratio_warn
#> [1] 0.03
#>
#> $profiles$strict$expected_var_min
#> [1] 0.3
#>
#> $profiles$strict$pca_first_eigen_warn
#> [1] 1.5
#>
#> $profiles$strict$pca_first_prop_warn
#> [1] 0.1
#>
#>
#> $profiles$standard
#> $profiles$standard$n_obs_min
#> [1] 100
#>
#> $profiles$standard$n_person_min
#> [1] 30
#>
#> $profiles$standard$low_cat_min
#> [1] 10
#>
#> $profiles$standard$min_facet_levels
#> [1] 3
#>
#> $profiles$standard$misfit_ratio_warn
#> [1] 0.1
#>
#> $profiles$standard$missing_fit_ratio_warn
#> [1] 0.2
#>
#> $profiles$standard$zstd2_ratio_warn
#> [1] 0.1
#>
#> $profiles$standard$zstd3_ratio_warn
#> [1] 0.05
#>
#> $profiles$standard$expected_var_min
#> [1] 0.2
#>
#> $profiles$standard$pca_first_eigen_warn
#> [1] 2
#>
#> $profiles$standard$pca_first_prop_warn
#> [1] 0.1
#>
#>
#> $profiles$lenient
#> $profiles$lenient$n_obs_min
#> [1] 60
#>
#> $profiles$lenient$n_person_min
#> [1] 20
#>
#> $profiles$lenient$low_cat_min
#> [1] 5
#>
#> $profiles$lenient$min_facet_levels
#> [1] 2
#>
#> $profiles$lenient$misfit_ratio_warn
#> [1] 0.15
#>
#> $profiles$lenient$missing_fit_ratio_warn
#> [1] 0.3
#>
#> $profiles$lenient$zstd2_ratio_warn
#> [1] 0.15
#>
#> $profiles$lenient$zstd3_ratio_warn
#> [1] 0.08
#>
#> $profiles$lenient$expected_var_min
#> [1] 0.1
#>
#> $profiles$lenient$pca_first_eigen_warn
#> [1] 3
#>
#> $profiles$lenient$pca_first_prop_warn
#> [1] 0.2
#>
#>
#>
#> $pca_reference_bands
#> $pca_reference_bands$eigenvalue
#> critical_minimum caution common strong
#> 1.4 1.5 2.0 3.0
#>
#> $pca_reference_bands$proportion
#> minor caution strong
#> 0.05 0.10 0.20
#>
#>
#> attr(,"class")
#> [1] "mfrm_threshold_profiles" "list"
vis <- build_visual_summaries(fit_bias, diag_bias, threshold_profile = "standard")
vis$warning_map$residual_pca_overall
#> [1] "Threshold profile: standard (PC1 EV >= 2.0, variance >= 10%)."
#> [2] "Heuristic reference bands: EV >= 1.4 (critical minimum), >= 1.5 (caution), >= 2.0 (common), >= 3.0 (strong); variance >= 5% (minor), >= 10% (caution), >= 20% (strong)."
#> [3] "Current exploratory PC1 checks: EV>=1.5:Y, EV>=2.0:Y, EV>=3.0:Y, Var>=10%:Y, Var>=20%:Y."
#> [4] "Overall residual PCA PC1 exceeds the current heuristic eigenvalue band (3.22)."
#> [5] "Overall residual PCA PC1 explains 20.1% variance."The same example_bias dataset also carries a
Group variable so DIF-oriented examples can show a non-null
pattern instead of a fully clean result. It can be loaded either with
load_mfrmr_data("example_bias") or
data("mfrmr_example_bias", package = "mfrmr").
spec <- specifications_report(fit, title = "Study run")
data_qc <- data_quality_report(
fit,
data = ej2021_study1,
person = "Person",
facets = c("Rater", "Criterion"),
score = "Score"
)
iter <- estimation_iteration_report(fit, max_iter = 8)
subset_rep <- subset_connectivity_report(fit, diagnostics = diag)
facet_stats <- facet_statistics_report(fit, diagnostics = diag)
cat_structure <- category_structure_report(fit, diagnostics = diag)
cat_curves <- category_curves_report(fit, theta_points = 101)
bias_rep <- bias_interaction_report(bias, top_n = 20)
plot_bias_interaction(bias_rep, plot = "scatter")The package also supports a separate simulation/prediction layer. The key distinction is:
evaluate_mfrm_design() and
predict_mfrm_population() are design-level helpers that
summarize expected operating characteristics under an explicit
simulation specification.predict_mfrm_units() and
sample_mfrm_plausible_values() score future or partially
observed persons under a fixed MML calibration.sim_spec <- build_mfrm_sim_spec(
n_person = 30,
n_rater = 4,
n_criterion = 4,
raters_per_person = 2,
assignment = "rotating"
)
pred_pop <- predict_mfrm_population(
sim_spec = sim_spec,
reps = 2,
maxit = 10,
seed = 1
)
#> Warning: Optimizer did not fully converge (code = 1, status = iteration_limit).
#> Optimizer reached the iteration limit before the terminal gradient became small
#> enough for review-only acceptance. Consider increasing maxit (current: 10) or
#> relaxing reltol (current: 1e-06).
#> Warning: Optimizer did not fully converge (code = 1, status = iteration_limit).
#> Optimizer reached the iteration limit before the terminal gradient became small
#> enough for review-only acceptance. Consider increasing maxit (current: 10) or
#> relaxing reltol (current: 1e-06).
summary(pred_pop)$forecast[, c("Facet", "MeanSeparation", "McseSeparation")]
#> # A tibble: 3 × 3
#> Facet MeanSeparation McseSeparation
#> <chr> <dbl> <dbl>
#> 1 Criterion 1.87 0.076
#> 2 Person 2.03 0.027
#> 3 Rater 0.728 0.728
keep_people <- unique(toy$Person)[1:18]
toy_mml <- suppressWarnings(
fit_mfrm(
toy[toy$Person %in% keep_people, , drop = FALSE],
person = "Person",
facets = c("Rater", "Criterion"),
score = "Score",
method = "MML",
quad_points = 5,
maxit = 15
)
)
new_units <- data.frame(
Person = c("NEW01", "NEW01"),
Rater = unique(toy$Rater)[1],
Criterion = unique(toy$Criterion)[1:2],
Score = c(2, 3)
)
pred_units <- predict_mfrm_units(toy_mml, new_units, n_draws = 0)
pv_units <- sample_mfrm_plausible_values(toy_mml, new_units, n_draws = 2, seed = 1)
summary(pred_units)$estimates[, c("Person", "Estimate", "Lower", "Upper")]
#> # A tibble: 1 × 4
#> Person Estimate Lower Upper
#> <chr> <dbl> <dbl> <dbl>
#> 1 NEW01 -0.097 -1.36 1.36
summary(pv_units)$draw_summary[, c("Person", "Draws", "MeanValue")]
#> # A tibble: 1 × 3
#> Person Draws MeanValue
#> <chr> <dbl> <dbl>
#> 1 NEW01 2 0