Skip to contents

check_asymmetry() takes an N x k binary ratings matrix and returns a scalar delta_hat (in percentile points, "pp"): the max-min spread of surface percentiles across the four agreement coefficients (PABAK, AC1, Fleiss kappa, Krippendorff alpha) when each is positioned on its calibrated reference surface. ICC is reported on the panel rows but excluded from delta_hat (its reference is distribution-sensitive in ways the agreement family is not).

Usage

check_asymmetry(
  ratings,
  axis = c("inter", "intra"),
  occasion = NULL,
  delta_thresholds = NULL,
  ...
)

Arguments

ratings

User input: an N x k binary matrix, an N x k data.frame whose columns are 0/1 / logical / 2-level factor, or a list of two equal-length 0/1 vectors (k = 2 paired form). See ?normalize_ratings for accepted shapes.

axis

"inter" (default) or "intra". Selects the surface family.

occasion

Reserved for axis = "intra" (a vector / factor identifying viewing occasion); ignored when axis = "inter".

delta_thresholds

Length-2 numeric vector c(caution, divergent) in percentile points. Default c(9.25, 11.75) from paper Sec.3.2 (NP optimum at alpha = 0.05 / 0.01).

...

Forwarded to position_on_surface() (e.g. bands, band_labels, reference_type).

Value

An S3 object of class grass_asymmetry_panel with fields:

  • delta_hat: scalar percentile-spread in pp

  • flag: one of "aligned", "caution", "divergent"

  • thresholds: named numeric vector of the (caution, divergent) cutoffs, in pp

  • panel: data.frame with coefficient, observed, percentile_pp

  • notes: character vector of unique caveats from the underlying surface positioning calls (e.g. nearest-neighbor gaps, ICC unavailability)

Details

delta_hat is a split-bias detector. It fires when raters tilt in different directions across (Se, Sp) – e.g., one rater high-Se / low-Sp, another high-Sp / low-Se – because the four coefficients respond to heterogeneous per-rater behavior differently and end up disagreeing on where the panel sits on the surface. The framework's other failure mode, shared/uniform bias (every rater tilts the same direction, e.g., a panel trained on one protocol all favoring specificity over sensitivity), produces uniform percentile degradation across coefficients: small delta_hat, low minimum surface percentile. Shared bias is detected by the panel's minimum surface percentile, not by delta_hat. A divergent flag therefore identifies a specific kind of disagreement – cross-coefficient inversion from heterogeneous rater behavior – and routes the user to the per-rater pairwise PABAK matrix and pooled-reference (Se_tilde, Sp_tilde) diagnostic.

Each coefficient is positioned on its reference surface via position_on_surface(), yielding a percentile in [0, 100] pp. The panel diagnostic is delta_hat = max(percentile) - min(percentile), computed over coefficients whose observed value sits within the achievable range of their reference surface (see Surface-envelope clamp below).

Surface-envelope clamp (v0.2.1+)

If an observed coefficient value falls outside the achievable range of its reference surface at the study's design (pi_hat, k, N), the inversion to q_hat clamps to the boundary and the percentile lands at exactly 0 or 100. Including such clamped percentiles in the max-min delta_hat would inflate the panel-spread purely because of the clamp, not because the panel disagrees on percentile. Since v0.2.1 the function therefore excludes clamped coefficients from delta_hat whenever at least two unclamped coefficients remain. The affected coefficients are still shown in the returned panel data.frame with clamped = TRUE and surface percentile 0 or 100, and a note in $notes names which coefficients were excluded. This matters most often for ICC at N > 200 (the bundled fitted-ICC reference is calibrated through N = 200; beyond that the function falls back to the oracle reference, which over-predicts the practitioner's GLMM-fit ICC and therefore clamps). The behavior guarantees that a divergent flag always reflects genuine cross-coefficient surface-percentile disagreement rather than an envelope artifact; the trade-off is that a coefficient with no calibrated reference at the user's design contributes nothing to the diagnostic. If fewer than two unclamped coefficients remain, delta_hat falls back to the raw spread including clamped values and the note records the fallback.

Tier thresholds default to c(9.25, 11.75) pp, the Neyman-Pearson-motivated size-alpha cutoffs at alpha = 0.05 and alpha = 0.01 from Sec.3.2 of the GRASS paper (see also App G operating characteristics). The construction is NP-optimal within the test class of threshold rules on delta_hat; it is not a likelihood-ratio test on the joint distribution of the panel coefficients (delta_hat is a paired-margin difference, not a likelihood ratio). The three flags are:

  • aligned (delta_hat < 9.25 pp): the panel agrees on the surface position. Any single coefficient is a stable summary; the primary coefficient (Table 2) carries the headline.

  • caution (9.25 <= delta_hat < 11.75 pp): the panel is mildly inconsistent. Report the primary coefficient with a caution flag and the delta_hat value.

  • divergent (delta_hat >= 11.75 pp): no single coefficient is a stable summary. Use latent_class_fit() to recover per-rater (Se, Sp) and report those instead.

The new check_asymmetry(ratings, ...) signature replaces the v0.1.x check_asymmetry(se, sp, ...) per-rater signature. For backward compatibility, calling check_asymmetry() with se = ... and sp = ... named arguments emits a one-time deprecation hint and routes the call to check_rater_asymmetry(). Supplying both ratings = ... and per-rater se = / sp = is an error.

References

Neyman, J. and Pearson, E. S. (1933). On the problem of the most efficient tests of statistical hypotheses. Philosophical Transactions of the Royal Society of London A, 231, 289-337.

See also

check_rater_asymmetry() for the per-rater Se/Sp companion; latent_class_fit() for the divergent-branch recovery of per-rater (Se, Sp); position_on_surface() for the underlying surface positioning.

Examples

# \donttest{
set.seed(1)
# Build a 5x200 symmetric panel -- should print as 'aligned'.
Y <- matrix(rbinom(5 * 200, 1, 0.30), nrow = 200, ncol = 5)
check_asymmetry(Y)
#> GRASS panel asymmetry diagnostic
#> 
#>   delta_hat = 3.1 pp
#>   flag      = aligned  (< 9.2)
#> 
#>   panel:
#>     coefficient        observed   percentile (pp)   in delta_hat
#>     pabak              0.16       47.5             yes
#>     mean_ac1           0.27       46.2             yes
#>     fleiss_kappa       0.00       49.3             yes
#>     icc                0.00       0.0             no [distribution-sensitive]
#> 
#>   Surface caveats:
#>     - Fitted-ICC F_key picked via glmer: mu_hat=-0.831, tau2_hat=0.011 -> F_key tau2=0.0625, mu=-0.847.
#>     - Fitted-ICC reference (GLMM-gap corrected) at F_key=LN_mu=-0.847_tau2=0.0625, k=5, N=200 (family=logit_normal, M1=0.303).
#>     - obs_value 0.0034 below achievable minimum (0.0834); q_hat clamped.
#>     - Delta-method SE undefined: dE/dq near zero at q_hat.
#>     - delta_hat is computed over the agreement family (PABAK, AC1, Fleiss, alpha). ICC is reported on the panel but does not enter delta_hat (v0.5.0 scope: ICC's reference surface depends on the full subject-prevalence distribution F and does not share the (q, pi_+) sufficient statistic the agreement family does).
# }