Skip to contents

screen_gllvmTMB() is a formula-aware pre-fit screen. It summarises response and formula conditions before fitting a stacked-trait GLLVM. The screen is advisory: it does not fit the model, remove traits, choose a latent rank, prove identifiability, or guarantee convergence. Binary/binomial screening is implemented. Non-binary modules, optional comparator checks, and high-dimensional benchmarks are not currently part of this function.

Usage

screen_gllvmTMB(
  formula,
  data,
  family,
  unit = NULL,
  trait = "trait",
  weights = NULL,
  missing = miss_control(),
  control = screen_control(),
  Xcoef_fixed = NULL,
  known_groups = NULL
)

Arguments

formula

A gllvmTMB() formula. Wide data can use traits() on the left-hand side; long data should use a response column on the left-hand side plus trait =.

data

A data frame.

family

A response family. Version 1 screens single-family binomial() fits with logit, probit, or cloglog links.

unit

Optional unit/grouping column. If omitted, the first covariance-structure grouping column is used when available.

trait

Trait column for long data. Wide traits() calls create this column internally.

weights

Optional weights vector, with the same binomial trial-count semantics as gllvmTMB() for long-format binomial fits.

missing

Missing-data control; defaults to miss_control().

control

A screen_control() object.

Xcoef_fixed

Optional named structural-zero fixed-effect constraints, normalized against the expanded fixed-effect columns as in gllvmTMB(). This argument is used by the opt-in fixed-design separation screen.

known_groups

Optional named list of character vectors of trait names, each with at least two distinct names (duplicated names within one group are an error). Each element declares a set of traits the user believes forms an exact one-hot (simplex) block or one or more exact pairwise containment (nesting) relations – for example the dummy columns of one categorical review-type or geographic-scope variable, or a broad-realm indicator together with one or more narrower nested realms. Each declared group is checked against the observed complete rows with an exact deterministic test: row sums for a one-hot block, or, for nesting, EVERY pairwise containment among the declared members (so it does not matter which order – or how many mutually incomparable narrower members – the group happens to be written in). When the relations found form a single total chain, the certificate reports that chain; when they form a partial order instead (for example one broad member containing two mutually incomparable narrower ones), every relation found is named and the group still fails as nesting. A group whose members are all constant on the complete rows is reported separately (not as nesting: a containment test is vacuously true against a constant and would not be genuine evidence); a member that is constant while other members of the same group are not is excluded from every pairwise comparison for the same reason. The one-hot test is not whole-group only: when the WHOLE declared group does not sum to 1 (for example a genuine one-hot block declared together with one unrelated trait), a bounded exhaustive search checks every subset of size 2 or more, smallest first, and reports each MINIMAL one-hot subset found as its own certificate – A + B + C = 1 is reported once even inside a larger declared group, never also as a redundant superset. This search is attempted only when the declared group has at most 12 members (2^12 - 13 = 4083 subset checks, microseconds even for many rows; declared groups are small by construction – one categorical variable's dummy columns or one nesting relation). A group larger than that bound is never silently reported PASS: the whole-group one-hot and pairwise nesting checks still run, but an explicit known_group_subset_not_attempted row records that the subset search itself was skipped for size, so a "no subset found" result can be told apart from "not looked for". A subset that sums to 1 only because every one of its members is constant is not reported (the same guard as the whole-group case). Each result is its own row in the response_dependencies table, independent of the automatic affine-rank screen below – except that a declared one-hot block, including a certified subset, also counts toward that screen's unresolved affine-dependency count (a nesting relation never does: it is an inequality, not an exact affine relation among the columns). Screening is Bernoulli-only, matching the automatic screen.

Value

A gllvmTMB_screen object. Use screen_table() to extract report-ready tables.

Details

The first implemented module covers binomial traits. It distinguishes Bernoulli responses from multi-trial binomial responses, reports the relevant denominators, and flags constants, sparse minority outcomes, duplicate or near-duplicate binary traits, rank-deficient fixed-effect designs, and grouping/rank conditions that should be inspected before interpretation. In systematic maps, a trait may be a content item or indicator. In a binary JSDM, a trait may be a species presence-absence response. Rare or constant species are flagged for inspection and possible sensitivity analysis, not automatically removed.

The screen also checks the response side for exact higher-order dependencies that the pairwise duplicate/complement check cannot see – most commonly a one-hot/simplex block, where several trait columns are really the dummy coding of one categorical variable and sum to exactly 1 on every complete row (a review-type, geographic-scope, or temporal-scope set is a typical source). It works by an affine-rank check on the augmented response matrix M = cbind(1, Y) over complete Bernoulli rows (rows where every screened trait is observed), using base R's qr() with tolerance sqrt(.Machine$double.eps) * max(dim(M)) (the usual dimension-scaled machine-precision rule, so the check tightens automatically on a larger response matrix rather than using one fixed constant regardless of size). The $design table's response_affine_rank row reports the matrix's rank (value) and its column count (threshold, = ncol(M)); a rank deficiency – threshold - value – means at least one exact affine dependency exists among the traits. The $response_dependencies table then adds, where cheaply recoverable from the matrix's null space, a human-readable certificate naming the traits and the relation (for example "A + B + C = 1"). This is a best-effort report, not exhaustive minimal-subset discovery: with more than one simultaneous exact dependency the automatic search can fail to decompose the null space into individually clean certificates, in which case the remaining deficiency is reported without a certificate (type = "unresolved"), never silently dropped. Declaring known structure via known_groups sidesteps that limitation with an exact, deterministic, per-group check. An exact one-hot block is not itself a bug to silently filter – it is one categorical variable, and belongs in multinomial() or a deliberate reference-level coding, not in several unconstrained binary traits.

With screen_control(separation = "fixed"), the screen uses the optional detectseparation package to classify the observed fixed design. This includes finite known offsets, whose presence is recorded in the returned separation table. The offset does not change the fixed-design recession directions used by the certificate. This is diagnostic support only: gllvmTMB() currently rejects nonzero offsets for binomial responses.

This certificate covers fixed-effect geometry only. It does not establish finiteness of latent loadings or covariance parameters, validate the full marginal GLLVM likelihood, or select a penalized estimator.

References

Albert A, Anderson JA (1984). On the existence of maximum likelihood estimates in logistic regression models. Biometrika 71:1–10. doi:10.1093/biomet/71.1.1.

Peduzzi P, Concato J, Kemper E, Holford TR, Feinstein AR (1996). A simulation study of the number of events per variable in logistic regression analysis. Journal of Clinical Epidemiology 49:1373–1379. doi:10.1016/S0895-4356(96)00236-3.

Vittinghoff E, McCulloch CE (2007). Relaxing the rule of ten events per variable in logistic and Cox regression. American Journal of Epidemiology 165:710–718. doi:10.1093/aje/kwk052.

Chalmers RP (2012). mirt: A multidimensional item response theory package for the R environment. Journal of Statistical Software 48(6):1–29. doi:10.18637/jss.v048.i06.

Kosmidis I, Schumacher D, Schwendinger F (2026). detectseparation: Detect and Check for Separation and Infinite Maximum Likelihood Estimates. R package version 0.4.0. doi:10.32614/CRAN.package.detectseparation.

Examples

df <- data.frame(
  study = factor(seq_len(12)),
  a = c(rep(1, 10), 0, 0),
  b = c(rep(1, 10), 0, 0),
  c = rep(c(0, 1), 6)
)
# The wrapper keeps the rendered example focused on the screen tables;
# inspect warnings in interactive work.
scr <- suppressWarnings(screen_gllvmTMB(
  traits(a, b, c) ~ 1 + latent(1 | study, d = 2),
  data = df,
  unit = "study",
  family = binomial()
))
screen_table(scr, "traits")
#>   trait response_mode status severity n_obs n_valid n_units n_success n_failure
#> 1     a     bernoulli   WARN   strong    12      12      12        10         2
#> 2     b     bernoulli   WARN   strong    12      12      12        10         2
#> 3     c     bernoulli   WARN moderate    12      12      12         6         6
#>   total_trials prevalence minority_rate minority_count info_fraction invalid_n
#> 1           12  0.8333333     0.1666667              2     0.5555556         0
#> 2           12  0.8333333     0.1666667              2     0.5555556         0
#> 3           12  0.5000000     0.5000000              6     1.0000000         0
#>    action                                           message
#> 1 inspect the minority outcome has very few observed trials
#> 2 inspect the minority outcome has very few observed trials
#> 3 inspect      the minority outcome has few observed trials
screen_table(scr, "recommendations")
#>                 scope status             action trait
#> 1               trait   WARN            inspect     a
#> 2               trait   WARN            inspect     b
#> 3               trait   WARN            inspect     c
#> 4                pair   FAIL collapse_or_recode a / b
#> 5                pair   WARN            inspect a / c
#> 6                pair   WARN            inspect b / c
#> 7              design   FAIL            inspect  <NA>
#> 8 response_dependency   FAIL collapse_or_recode  a, b
#>                                                                                                                                                        evidence
#> 1                                                                                                             the minority outcome has very few observed trials
#> 2                                                                                                             the minority outcome has very few observed trials
#> 3                                                                                                                  the minority outcome has few observed trials
#> 4                                                                                                            the two traits are exact duplicates on paired rows
#> 5                                                                                                             the two traits are near-duplicates on paired rows
#> 6                                                                                                             the two traits are near-duplicates on paired rows
#> 7 response matrix augmented with an intercept is rank deficient by 1 on 12 complete rows: at least one exact affine dependency exists among the screened traits
#> 8          b = a: this affine dependency is already reported at trait/pair level (a duplicate pair) and was projected out before the one-hot certificate search
#>                                                                                                                                                                    model_implication
#> 1                                                                                                          inspect coding, missingness, and latent-response inclusion before fitting
#> 2                                                                                                          inspect coding, missingness, and latent-response inclusion before fitting
#> 3                                                                                                          inspect coding, missingness, and latent-response inclusion before fitting
#> 4                                                                                                           inspect whether both traits should enter the first latent-response block
#> 5                                                                                                           inspect whether both traits should enter the first latent-response block
#> 6                                                                                                           inspect whether both traits should enter the first latent-response block
#> 7                                                                                                                                                 inspect the formula before fitting
#> 8 this is one categorical variable coded as several binary columns; keep it out of the latent block as-is, and either recode it as multinomial() or fix a deliberate reference level