Skip to contents

Compute a Mantel–Haenszel (MH) odds ratio for each declared target, with conditional exact or asymptotic inference. Matching strata are supplied explicitly; this function does not estimate ability or fit an MFRM.

Usage

mantel_haenszel_table(
  data,
  person,
  target,
  score,
  group,
  strata,
  groups,
  inference = c("exact", "asymptotic"),
  correct = TRUE,
  conf_level = 0.95,
  p_adjust = "holm"
)

Arguments

data

Long-format data with at most one row per Person and target.

person

Name of the independent Person identifier column.

target

Name of the item or other target identifier column.

score

Name of a numeric column containing only 0, 1 or missing values. No automatic dichotomization or category recoding is performed.

group

Name of the group column. Each Person must belong to one group.

strata

Names of one or more columns jointly defining exact matching strata, for example c("Total", "Plan"). Numeric values are not binned. Strata can differ across targets. Missing strata exclude that response.

groups

Two distinct group labels in reference, focal order. Data containing other groups are rejected rather than silently filtered.

inference

"exact" (default) uses the conditional distribution given each stratum's margins. "asymptotic" uses the MH chi-squared approximation.

correct

Logical; request the continuity correction convention of stats::mantelhaen.test() for asymptotic inference. Ignored for exact inference; the resolved setting is saved. This does not correct for repeated ratings, matching errors or multiple testing.

conf_level

Confidence level strictly between 0 and 1. Intervals are pointwise, not simultaneous across targets.

p_adjust

A stats::p.adjust() method, default "holm". The family includes every observed target, including targets with unavailable tests.

Value

A plain list with table (one row per target), strata (2-by-2 counts and stratum odds ratios), cases (input-row inclusion audit), matching (unique complete stratum keys), settings and notes. Stratum indexes rows of matching. Included means inclusion in the conditional calculation, not proven substantive comparability. PAdjusted uses the family specified above; interval endpoints are not multiplicity-adjusted. Numerical availability does not certify a DIF inference. Save with base::saveRDS() and export each data frame with utils::write.csv(); reading these outputs performs no calculation.

Details

An odds ratio above 1 means higher odds of score 1 in the reference group. MHOddsRatio is always sum(AD/N)/sum(BC/N), with reference successes A, reference failures B, focal successes C and focal failures D. No .5 is added to zero cells. Zero and infinite estimates are retained.

OddsRatio and its interval follow the selected inference: conditional maximum likelihood and an exact equal-tail interval for "exact", or the MH estimate and a large-sample log-odds interval for "asymptotic". Exact two-sided p-values sum null probabilities no greater than the observed statistic's probability, as in stats::mantelhaen.test(). They need not invert the equal-tail interval. Asymptotic boundary estimates can have an unavailable interval even when the test and point estimate are available. No method is substituted automatically. Computation failures and warnings remain visible in Status/Message. Exact refers to the conditional distribution; numerical inversion uses the standard R routine's root-finding precision. Its asymptotic continuity correction subtracts .5 only when the absolute count contrast is at least .5. Exact p-values exceeding 1 by at most 64 machine epsilons from rounding are returned as 1; larger violations remain unavailable. Asymptotic count products use double precision to avoid integer overflow in large strata. This preserves the MH formulas and does not change the independent-Person or large-sample assumptions.

A stratum contributes information only when both groups and both score categories occur. Other strata are retained with their counts and a reason but contribute neither odds-ratio terms nor inference. This also removes empty and singleton strata before calling the standard R calculation. A single informative stratum is supported. cases retains every input row, distinguishing missing responses/matching from uninformative strata. Duplicate Person-target cells, including missing-score duplicates, are rejected. Multiple targets may use the same Persons; dependence across targets does not invalidate Holm adjustment of valid individual p-values.

The inferential model requires independent Persons within each target and a common conditional odds ratio across its strata. Small cells alone do not invalidate the exact conditional calculation, but exact inference does not establish these assumptions. The separate stratum odds ratios help reveal opposing effects that a common MH effect can conceal; no test of homogeneity, power guarantee, ETS label or automatic DIF/bias flag is given. The number of independent Persons is not the number of rating rows.

Interpreting conditional association as DIF additionally requires adequate matching and comparable exposure. With a common binary Rasch item set and invariant other items, the total including the studied item eliminates the group ability distribution from that item's conditional response. A rest score generally does not have this property. Totals from different rater/task plans are not automatically comparable: supply justified joint strata or restrict to a defensible common plan. Strata without group overlap are visibly excluded. The function verifies data structure, not the validity of a matching variable, invariance of other items, absence of informative missingness, or independence beyond the supplied Person IDs.

A rater scoring several criteria for the same Person produces repeated Person-rater observations and cannot be pooled through this interface. Renaming those observations as new Persons does not establish independence. This is a separate conditional association analysis, not a new method for analyze_dff(). Residual and linked-refit contrasts have different targets; their agreement does not certify robustness or fairness.

References

Holland, P. W., & Thayer, D. T. (1986). Differential item functioning and the Mantel-Haenszel procedure. ETS Research Report RR-86-31, pp. 7–18. doi:10.1002/j.2330-8516.1986.tb00186.x . See stats::mantelhaen.test() for the numerical inference conventions.

Examples

# One binary target per Person; both groups share two declared strata.
d <- data.frame(Person = paste0("P", 1:16), Item = "A",
  Group = rep(c("Reference", "Focal"), each = 8),
  Matching = rep(rep(c("Low", "High"), each = 4), 2),
  Score = c(0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1))
mh <- mantel_haenszel_table(d, "Person", "Item", "Score", "Group",
                           "Matching", c("Reference", "Focal"))
mh$table
#>   Target Reference Focal NReference NFocal InputRows CompleteRows ExcludedRows
#> 1      A Reference Focal          8      8        16           16            0
#>   InformativeStrata MHOddsRatio OddsRatio     Lower    Upper ConfidenceLevel
#> 1                 2           3  2.601683 0.2547306 38.55288            0.95
#>    EstimateMethod ChiSquared DF   PValue    Status IntervalStatus Message
#> 1 conditional_mle         NA NA 0.622449 available      available        
#>   PAdjusted
#> 1  0.622449
mh$strata
#>   Target Stratum ReferenceSuccess ReferenceFailure FocalSuccess FocalFailure N
#> 1      A       1                3                1            2            2 8
#> 2      A       2                2                2            1            3 8
#>   OddsRatio Informative      Reason
#> 1         3        TRUE informative
#> 2         3        TRUE informative