Skip to contents

latent_class_fit() is the divergent-branch fallback for the GRASS Reporting Card. When the cross-coefficient panel disagrees, the framework abandons the single q_hat summary and reports per-rater (Se_j, Sp_j) instead. This function fits those per-rater accuracy parameters from an N x k binary rating matrix.

Usage

latent_class_fit(
  ratings,
  B = 1000L,
  method = NULL,
  max_iter = 1000L,
  tol = 1e-06,
  seed = NULL,
  ...
)

Arguments

ratings

An N x k binary rating matrix. Rows are subjects, columns are raters, values in {0, 1}. Data.frame and list-of-rater- columns inputs are coerced. Requires N >= 10, k >= 2, no NA, no all-constant columns.

B

Integer >= 0. Number of nonparametric bootstrap replicates. B = 0 skips the bootstrap and returns the EM point estimate (or bounds at k = 2) without CIs.

method

One of "dawid_skene_em", "hui_walter", or NULL (default). When NULL, dispatches to Hui-Walter at k = 2 and to Dawid-Skene EM at k >= 3. Supplying "dawid_skene_em" at k = 2 errors – the EM is unidentified there.

max_iter

Integer. EM iteration cap. Default 1000.

tol

Numeric. EM log-likelihood tolerance. Default 1e-6.

seed

Optional integer. Sets the bootstrap RNG; the EM itself is deterministic.

...

Reserved for future extensions; currently ignored.

Value

An S3 object of class c("grass_latent_class", "list"):

  • per_rater: data.frame with rater, se_hat, sp_hat (NA at k = 2), se_lower, se_upper, sp_lower, sp_upper, bound_only (TRUE at k = 2).

  • method: "dawid_skene_em" or "hui_walter".

  • converged: logical (NA at k = 2).

  • iterations: integer (NA at k = 2).

  • B: integer; bootstrap replicates run.

  • prevalence_hat: numeric estimated prevalence (NA at k = 2).

  • log_likelihood: numeric (NA at k = 2).

Details

Two regimes, dispatched by k:

  • k >= 3: Dawid-Skene 1979 expectation-maximization. Latent binary class C_i in {0, 1}; conditional independence of raters given C; parameters (pi, Se_j, Sp_j) for j = 1..k. Initialized from majority-vote consensus. Iterated to log-likelihood tolerance tol or max_iter. Hand-rolled in base R, no new package dependency.

  • k == 2: Hui-Walter 1980 inequality bounds. Per-rater Se and Sp are NOT point-identified from a single 2x2 table without external information (e.g., a known-prevalence subgroup or a reference standard). We return the inequality bounds the observed marginals support: with rater j positive rate P_j, Se_j is bounded below by P_j, Sp_j is bounded below by 1 - P_j, both above by 1. The returned rows have bound_only = TRUE and se_hat = sp_hat = NA. This is a documented limitation of the design, not a bug.

Bootstrap CI (when B > 0): nonparametric, subjects-with-replacement. At k >= 3 the EM is refit on each bootstrap sample; at k = 2 the bounds are recomputed and the bootstrap distribution is on the bound midpoints. Reports the empirical 2.5 / 97.5 percentiles on the per-rater Se_j and Sp_j (or their bound midpoints at k = 2).

References

Dawid, A. P. and Skene, A. M. (1979). Maximum likelihood estimation of observer error-rates using the EM algorithm. Applied Statistics, 28(1), 20–28.

Hui, S. L. and Walter, S. D. (1980). Estimating the error rates of diagnostic tests. Biometrics, 36(1), 167–171.

Examples

if (FALSE) { # \dontrun{
set.seed(1)
N <- 500; k <- 5
Se <- 0.90; Sp <- 0.85; pi <- 0.30
C <- rbinom(N, 1, pi)
Y <- matrix(0L, N, k)
for (j in seq_len(k))
  Y[, j] <- rbinom(N, 1, ifelse(C == 1, Se, 1 - Sp))
fit <- latent_class_fit(Y, B = 200, seed = 1)
print(fit)
} # }