
Build a category structure report (preferred alias)
Source:R/api-reports.R
category_structure_report.RdBuild a category structure report (preferred alias)
Usage
category_structure_report(
fit,
diagnostics = NULL,
theta_range = c(-6, 6),
theta_points = 241,
drop_unused = FALSE,
include_fixed = FALSE,
fixed_max_rows = 200
)Arguments
- fit
Output from
fit_mfrm().- diagnostics
Optional matching output from
diagnose_mfrm(). Reuses stored uncertainty and marginal-fit results; omitted diagnostics do not trigger a covariance calculation.- theta_range
Theta/logit range used to derive transition points.
- theta_points
Number of grid points used for transition-point search.
- drop_unused
If
TRUE, remove zero-count rows from the global category display. Owner-specific counts and their denominators remain complete.- include_fixed
If
TRUE, include a legacy-compatible fixed-width text block.- fixed_max_rows
Maximum rows per fixed-width section.
Details
Preferred high-level API for category-structure diagnostics. This wraps the legacy-compatible bar/transition export and returns a stable bundle interface for reporting and plotting.
Interpreting output
Key components include:
category usage and descriptive residual table; category ZSTD and fit flags are unavailable because outcome-selected residuals lack a unit baseline
threshold ordering and adjacent threshold gaps
category transition-point table on the requested theta grid
Practical read order:
summary(out)for compact warnings and threshold ordering.out$category_tablefor sparse/misfitting categories.out$median_thresholdsfor cumulative 50% boundaries and their range status;AndrichThresholdseparately retains adjacent-category steps.plot(out)for quick visual check.
owner_category_table, threshold_table, model_context and notes
follow rating_scale_table(), including source checks and uncertainty
status. The global usage display does not replace owner-specific counts.
curve_profiles maps each CurveGroup to its step/slope owners and levels.
Curves use zero additive facet locations. MedianThreshold now solves a
cumulative 50% boundary, replacing the old mislabeled adjacent-category step.
Recreate saved category structure reports; no calibration refit is needed.
Half-score crossings outside theta_range are NA with an explicit status.
Mode peaks describe the finite grid, not an unbounded global maximum.
Stored step SEs are reported only in threshold_table, not transferred to
modal, half-score or cumulative boundaries. Two-family GPCM remains
unsupported by this helper.
Counts support as_ggplot(); modal-boundary and half-score views require the
base renderer or explicitly grouped custom graphics from plot_data().
Typical workflow
fit_mfrm()-> model.diagnose_mfrm()-> residual/fit diagnostics (optional argument here).category_structure_report()-> category health snapshot.summary()andplot()for draft-oriented review of category structure.
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
out <- category_structure_report(fit)
summary(out)
#> mfrmr Category Structure Summary
#>
#> Category coverage
#> Categories Displayed Used Counts available Counts unavailable Flags
#> 4 4 4 4 0 0
#> Decisions available Decisions unavailable
#> 4 0
#>
#> Category rows
#> Category Count Percent Expected count Infit Outfit Infit ZSTD Outfit ZSTD
#> 1 139 18.099 139 1.806 1.602 NA NA
#> 2 241 31.380 241 0.613 0.780 NA NA
#> 3 252 32.812 252 0.556 0.617 NA NA
#> 4 136 17.708 136 1.871 1.590 NA NA
#> Category-structure diagnostics with mode boundaries and half-score reference
#> points.
#> Step owner: Common; selection: not_applicable.
#> A Step describes the transition between adjacent score categories, not a
#> learning stage or a pass/fail cut. At the corresponding predictor value, the
#> two categories have equal probability, not necessarily probability 0.5 each.
#> Stored step offsets and full ability-axis crossings differ when other facet
#> effects or interactions are included; check the reference profile and step
#> owner.
#> Category counts are observed ratings, not independent Persons. Owner
#> percentages use each owner's total weight; no-exposure percentages are
#> unavailable.
#> An unobserved category does not establish structural absence. Review the
#> rating plan and rubric before merging categories.
#> Step SEs describe the stored step offsets, not full ability-axis crossings,
#> adjacent-step gaps or decision cuts. No additional covariance calculation is
#> requested.
#> Legacy step uncertainty without full source identity is retained for review;
#> inspect SE_Status, CIUse and UncertaintySourceStatus.
#> Curves use zero-additive-facet reference profiles. MedianThreshold is a
#> cumulative 50% boundary; AndrichThreshold is an adjacent-category step.
#> MeanBoundaryTheta is unavailable outside theta_range. PeakTheta is a
#> finite-grid peak.
#> Category counts were available for all 4 categories: 0 unused and 0 below 10.
#> Counts alone do not establish category adequacy.
#> Flag counts describe available decisions in the displayed rows; unavailable
#> decisions do not indicate an absence of warnings.
head(out$category_table[, c("Category", "Count", "Infit", "Outfit")])
#> Category Count Infit Outfit
#> 1 1 139 1.8058056 1.6016256
#> 2 2 241 0.6130391 0.7800174
#> 3 3 252 0.5555312 0.6169201
#> 4 4 136 1.8705483 1.5900860
p_cs <- plot(out, draw = FALSE)
p_cs$data$plot
#> [1] "counts"