--- title: "Conformal Local Influence Screening with clis" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Conformal Local Influence Screening with clis} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.width = 7, fig.height = 4, dpi = 96 ) run_models <- requireNamespace("gamlss", quietly = TRUE) && requireNamespace("gamlss.dist", quietly = TRUE) ``` ## Motivation Classical local influence diagnostics rank observations by a curvature measure and ask the analyst to inspect an index plot for points that "stand out". This workflow has two well-known weaknesses. First, it does not scale: with thousands of observations, the index plot becomes unreadable and the underlying $n \times n$ eigenproblem becomes expensive. Second, it offers no control of the error rate: there is no principled threshold and no guarantee on the proportion of false declarations. The **clis** package addresses both problems for zero-or-one inflated beta (BIc) regression models. It uses the conformal normal curvature of an observation as a *non-conformity score* inside a split-conformal testing procedure. The result is a per-observation conformal $p$-value whose Benjamini-Hochberg adjustment controls the false discovery rate (FDR) at a level you choose, while running in linear time per observation after a single model fit. ## A worked example We use the bundled `vaccination` dataset: national DTP3 immunisation coverage proportions for 2022, with a point mass at one (countries with complete coverage). This dataset ships with the package so the vignette builds without external dependencies. The paper's applications use the `ReadingSkills` data from the `betareg` package (one-inflated, small sample) and the `lungFunction` data from the `gamlss.data` package (one-inflated, large sample); the scripts `data-raw/application-reading.R` and `data-raw/application-lung.R` reproduce them, and `data-raw/README.md` gives a runbook for all the paper's tables and figures. ```{r data} library(clis) vaccination <- load_vaccination() str(vaccination) mean(vaccination$dtp3 == 1) # fraction at the upper boundary ``` We fit a one-inflated beta model with variable dispersion: the inflation probability depends on the Human Development Index, the conditional mean on log GDP and urbanisation, and the precision on log GDP and log population. ```{r fit, eval = run_models} library(gamlss) fit <- gamlss( dtp3 ~ ln_gdp + urb, sigma.formula = ~ ln_gdp + ln_pop, nu.formula = ~ hdi, family = gamlss.dist::BEOI, data = vaccination, control = gamlss.control(trace = FALSE) ) ``` ## Screening with FDR control A single call performs the whole screening procedure. ```{r screen, eval = run_models} res <- clis_screen(fit, alpha = 0.1, seed = 1) res ``` The `influential_global` component gives the indices declared influential at the chosen FDR level. We can visualise the conformal $p$-values against the Benjamini-Hochberg boundary and the influence scores: ```{r plot-clis, eval = run_models} plot_clis(res) ``` ## Block decomposition Because the BIc information matrix is block diagonal between the inflation parameters and the mean/precision parameters, the influence of each observation decomposes additively into a part attributable to the inflation submodel and a part attributable to the conditional-mean/precision submodel. The `summary` method reports this attribution for the declared set. ```{r summary, eval = run_models} summary(res) ``` ## Classical CNC panels For comparison with the traditional workflow, the classical conformal normal curvature panels are available: ```{r cnc-panels, eval = run_models} info <- bic_info(fit) delta <- delta_caseweights(fit) cnc <- cnc_matrix(delta$Delta, info$info_inv) sc <- cnc_scores(cnc) dec <- cnc_block_decomp(delta, info) plot_cnc_panels(cnc, sc, dec) ``` ## Perturbation schemes Four schemes are available, each targeting a different structural aspect of the model. To screen specifically for observations that drive the heteroscedastic precision structure, use the precision-covariate scheme: ```{r prec, eval = run_models} res_prec <- clis_screen(fit, scheme = "preccovar", p = 2, alpha = 0.1, seed = 1) res_prec ``` ## A practical workflow In practice the recommended sequence is: (1) fit the model; (2) look at the classical influence index plot to see the shape of the influence, exactly as in the traditional beta-regression diagnostics; (3) run the conformal screen to obtain an error-controlled declaration; (4) use the block decomposition to localise the effect; (5) repeat over a few seeds for a stable report. ```{r workflow, eval = run_models} # (2) classical index plot -- the familiar picture, no error control plot_influence(fit, labels = vaccination$iso3c) # (3) error-controlled screen at FDR 10% res <- clis_screen(fit, alpha = 0.10, seed = 1) # (5) stability across seeds: keep declarations that persist decl <- lapply(1:10, function(s) clis_screen(fit, alpha = 0.10, seed = s)$influential_global) stable <- Reduce(intersect, decl) vaccination$iso3c[stable] ``` The index plot answers "what does the influence look like?"; the screen answers "which points can I declare influential while controlling the false discovery rate?"; the intersection over seeds gives a deterministic report. ## Why the guarantee holds The conformal $p$-values are marginally valid because, under the null that a screening point is exchangeable with the (clean) calibration set, the rank of its score is uniform. Bates and others (2023) showed that the resulting $p$-values are positively dependent, so the Benjamini-Hochberg procedure controls the FDR. The only modelling assumption beyond the BIc fit is that the calibration set is predominantly free of influential points, which holds approximately whenever influential observations are rare. ## Semiparametric fits When the covariate effects are nonlinear, the submodels can use penalised additive terms (for example P-splines via `pb()` in `gamlss`). The screening procedure then works on the penalised information `J + S`, and the false discovery rate guarantee is unchanged: only the numerical scores differ. Pass `penalised = TRUE` to `clis_screen()`, which extracts the penalty with `bic_penalty()` and reports the effective degrees of freedom. ```{r semipar, eval = FALSE} fit_s <- gamlss( dtp3 ~ pb(ln_gdp) + urb, sigma.formula = ~ pb(ln_gdp) + ln_pop, nu.formula = ~ pb(hdi), family = gamlss.dist::BEOI, data = vaccination, control = gamlss.control(trace = FALSE) ) res_s <- clis_screen(fit_s, alpha = 0.1, penalised = TRUE, seed = 1) res_s ``` The reported effective degrees of freedom replace the nominal parameter count and split into an inflation part and a mean/precision part, mirroring the block decomposition of the influence scores. ### Smoothing-parameter selection The smoothing parameters are chosen by the outer criterion of the `gamlss` fit (REML or GCV). For the false discovery rate guarantee to hold exactly, the smoothing parameter should not break the exchangeability of the calibration scores: selecting it on the calibration split, or on a separate auxiliary split, is sufficient. Selecting it on the full sample introduces only a mild dependence through a low-dimensional global quantity, whose effect on the realised FDR is negligible in practice. REML is the more stable default; GCV can undersmooth at small sample sizes.