Skip to contents

This is the package entry point. It wraps mfrm_estimate() and defaults to method = "MML". Any number of facet columns can be supplied via facets.

Usage

fit_mfrm(
  data,
  person,
  facets,
  score,
  rating_min = NULL,
  rating_max = NULL,
  weight = NULL,
  keep_original = FALSE,
  model = c("RSM", "PCM"),
  method = c("MML", "JML", "JMLE"),
  step_facet = NULL,
  anchors = NULL,
  group_anchors = NULL,
  noncenter_facet = "Person",
  dummy_facets = NULL,
  positive_facets = NULL,
  anchor_policy = c("warn", "error", "silent"),
  min_common_anchors = 5L,
  min_obs_per_element = 30,
  min_obs_per_category = 10,
  quad_points = 15,
  maxit = 400,
  reltol = 1e-06
)

Arguments

data

A data.frame with one row per observation.

person

Column name for the person (character scalar).

facets

Character vector of facet column names.

score

Column name for observed category score.

rating_min

Optional minimum category value.

rating_max

Optional maximum category value.

weight

Optional weight column name.

keep_original

Keep original category values.

model

"RSM" or "PCM".

method

"MML" (default) or "JML" / "JMLE".

step_facet

Step facet for PCM.

anchors

Optional anchor table.

group_anchors

Optional group-anchor table.

noncenter_facet

One facet to leave non-centered.

dummy_facets

Facets to fix at zero.

positive_facets

Facets with positive orientation.

anchor_policy

How to handle anchor-audit issues: "warn" (default), "error", or "silent".

min_common_anchors

Minimum anchored levels per linking facet used in anchor-audit recommendations.

min_obs_per_element

Minimum weighted observations per facet level used in anchor-audit recommendations.

min_obs_per_category

Minimum weighted observations per score category used in anchor-audit recommendations.

quad_points

Quadrature points for MML.

maxit

Maximum optimizer iterations.

reltol

Optimization tolerance.

Value

An object of class mfrm_fit (named list) with:

  • summary: one-row model summary (LogLik, AIC, BIC, convergence)

  • facets$person: person estimates (Estimate; plus SD for MML)

  • facets$others: facet-level estimates for each facet

  • steps: estimated threshold/step parameters

  • config: resolved model configuration used for estimation (includes config$anchor_audit)

  • prep: preprocessed data/level metadata

  • opt: raw optimizer result from stats::optim()

Details

Data must be in long format (one row per observed rating event).

Model

fit_mfrm() estimates the many-facet Rasch model (Linacre, 1989). For a two-facet design (rater \(j\), criterion \(i\)) the model is:

$$\ln\frac{P(X_{nij} = k)}{P(X_{nij} = k-1)} = \theta_n - \delta_j - \beta_i - \tau_k$$

where \(\theta_n\) is person ability, \(\delta_j\) rater severity, \(\beta_i\) criterion difficulty, and \(\tau_k\) the \(k\)-th Rasch-Andrich threshold. Any number of facets may be specified via the facets argument; each enters as an additive term in the linear predictor \(\eta\).

With model = "RSM", thresholds \(\tau_k\) are shared across all levels of all facets. With model = "PCM", each level of step_facet receives its own threshold vector \(\tau_{i,k}\) on the package's shared observed score scale.

With method = "MML", person parameters are integrated out using Gauss-Hermite quadrature and EAP estimates are computed post-hoc. With method = "JML", all parameters are estimated jointly as fixed effects. See the "Estimation methods" section of mfrmr-package for details.

Input requirements

Minimum required columns are:

  • person identifier (person)

  • one or more facet identifiers (facets)

  • observed score (score)

Scores are treated as ordered categories. If your observed categories do not start at 0, set rating_min/rating_max explicitly to avoid unintended recoding assumptions.

Supported model/estimation combinations:

  • model = "RSM" with method = "MML" or "JML"/"JMLE"

  • model = "PCM" with a designated step_facet (defaults to first facet)

Anchor inputs are optional:

  • anchors should contain facet/level/fixed-value information.

  • group_anchors should contain facet/level/group/group-value information. Both are normalized internally, so column names can be flexible (facet, level, anchor, group, groupvalue, etc.).

Anchor audit behavior:

  • fit_mfrm() runs an internal anchor audit.

  • invalid rows are removed before estimation.

  • duplicate rows keep the last occurrence for each key.

  • anchor_policy controls whether detected issues are warned, treated as errors, or kept silent.

Facet sign orientation:

  • facets listed in positive_facets are treated as +1

  • all other facets are treated as -1 This affects interpretation of reported facet measures.

Performance tips

For exploratory work, method = "JML" is usually faster than method = "MML", but it may require a larger maxit to converge on larger datasets.

For MML runs, quad_points is the main accuracy/speed trade-off:

  • quad_points = 7 is a good lightweight default for quick iteration.

  • quad_points = 15 gives a more stable approximation for final reporting.

Downstream diagnostics can also be staged:

  • use diagnose_mfrm(fit, residual_pca = "none") for a quick first pass

  • add residual PCA only when you need exploratory residual-structure evidence

Downstream diagnostics report ModelSE / RealSE columns and related reliability indices. For MML, non-person facet ModelSE values are based on the observed information of the marginal log-likelihood and person rows use posterior SDs from EAP scoring. For JML, these quantities remain exploratory approximations and should not be treated as equally formal.

Interpreting output

A typical first-pass read is:

  1. fit$summary for convergence and global fit indicators.

  2. summary(fit) for human-readable overviews.

  3. diagnose_mfrm(fit) for element-level fit, approximate separation/reliability, and warning tables.

Typical workflow

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

  2. Validate convergence and scale structure with summary(fit).

  3. Run diagnose_mfrm() and proceed to reporting with build_apa_outputs().

Examples

toy <- load_mfrmr_data("example_core")

fit <- fit_mfrm(
  data = toy,
  person = "Person",
  facets = c("Rater", "Criterion"),
  score = "Score",
  method = "JML",
  model = "RSM",
  maxit = 25
)
fit$summary
#> # A tibble: 1 × 11
#>   Model Method     N Persons Facets Categories LogLik   AIC   BIC Converged
#>   <chr> <chr>  <int>   <int>  <int>      <dbl>  <dbl> <dbl> <dbl> <lgl>    
#> 1 RSM   JMLE     768      48      2          4  -821. 1756. 2021. TRUE     
#> # ℹ 1 more variable: Iterations <int>
s_fit <- summary(fit)
s_fit$overview[, c("Model", "Method", "Converged")]
#> # A tibble: 1 × 3
#>   Model Method Converged
#>   <chr> <chr>  <lgl>    
#> 1 RSM   JMLE   TRUE     
p_fit <- plot(fit, draw = FALSE)
class(p_fit)
#> [1] "mfrm_plot_bundle" "list"            

# MML is the default:
fit_mml <- fit_mfrm(
  data = toy,
  person = "Person",
  facets = c("Rater", "Criterion"),
  score = "Score",
  model = "RSM",
  quad_points = 7,
  maxit = 25
)
summary(fit_mml)
#> Many-Facet Rasch Model Summary
#>   Model: RSM | Method: MML
#>   N: 768 | Persons: 48 | Facets: 2 | Categories: 4
#>   LogLik: -903.081 | AIC: 1824.161 | BIC: 1865.955
#>   Converged: Yes | Iterations: 51
#> 
#> Facet overview
#>      Facet Levels MeanEstimate SDEstimate MinEstimate MaxEstimate  Span
#>  Criterion      4            0      0.283      -0.408       0.243 0.651
#>      Rater      4            0      0.308      -0.323       0.328 0.651
#> 
#> Person measure distribution
#>  Persons  Mean    SD Median    Min   Max  Span MeanPosteriorSD
#>       48 0.033 1.009  0.002 -2.023 2.333 4.356           0.261
#> 
#> Step parameter summary
#>  Steps    Min   Max  Span Monotonic
#>      3 -1.301 1.347 2.648      TRUE
#> 
#> Most extreme facet levels (|estimate|)
#>      Facet    Level Estimate
#>  Criterion  Content   -0.408
#>      Rater      R04    0.328
#>      Rater      R02   -0.323
#>  Criterion Accuracy    0.243
#>      Rater      R01   -0.192
#> 
#> Highest person measures
#>  Person Estimate    SD
#>    P023    2.333 0.233
#>    P024    2.033 0.542
#>    P036    1.384 0.475
#>    P002    1.233 0.299
#>    P003    1.155 0.070
#> 
#> Lowest person measures
#>  Person Estimate    SD
#>    P015   -2.023 0.547
#>    P045   -1.375 0.468
#>    P008   -1.230 0.293
#>    P006   -1.178 0.168
#>    P026   -1.178 0.168
#> 
#> Notes
#>  - No immediate warnings from fit-level summary checks.

# Next steps after fitting:
diag_mml <- diagnose_mfrm(fit_mml, residual_pca = "none")
chk <- reporting_checklist(fit_mml, diagnostics = diag_mml)
head(chk$checklist[, c("Section", "Item", "DraftReady")])
#>          Section                   Item DraftReady
#> 1 Method Section    Model specification       TRUE
#> 2 Method Section       Data description       TRUE
#> 3 Method Section        Precision basis       TRUE
#> 4 Method Section            Convergence       TRUE
#> 5 Method Section  Connectivity assessed       TRUE
#> 6     Global Fit Standardized residuals       TRUE