Latent-class fit: per-rater Sensitivity and Specificity from a binary rating matrix
Source:R/latent_class.R
latent_class_fit.Rdlatent_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 = 0skips the bootstrap and returns the EM point estimate (or bounds at k = 2) without CIs.- method
One of
"dawid_skene_em","hui_walter", orNULL(default). WhenNULL, 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 withrater,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
tolormax_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_jis bounded below byP_j,Sp_jis bounded below by1 - P_j, both above by 1. The returned rows havebound_only = TRUEandse_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
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)
#> grass latent-class fit
#> method : dawid_skene_em
#> raters (k) : 5
#> bootstrap B : 200
#> converged : TRUE
#> iterations : 14
#> prevalence_hat: 0.281
#> log-likelihood: -1264.374
#> per-rater
#> R1 Se = 0.917 (0.860, 0.966) Sp = 0.841 (0.801, 0.886)
#> R2 Se = 0.963 (0.925, 0.993) Sp = 0.834 (0.798, 0.874)
#> R3 Se = 0.911 (0.856, 0.957) Sp = 0.819 (0.772, 0.855)
#> R4 Se = 0.927 (0.875, 0.973) Sp = 0.848 (0.812, 0.888)
#> R5 Se = 0.898 (0.841, 0.953) Sp = 0.837 (0.802, 0.873)