Test Constancy and Assess Logistic Trend-Filtering Prediction
Source:R/logistic_trend_filtering_assessment.R
assess.logistic.trend.filtering.RdAssess whether an order-2 logistic trend filter detects a nonconstant binary probability, and separately estimate predictive improvement over a constant. This is an additional assessment, not an option that changes the fitted objective or supplies confidence bands.
Arguments
- object
A
logistic.trend.filtering.fitwith independent binary observations, unit weights, no covariates and no offset. Predictor choice, penalty path, ridge penalties and solver settings must have been specified independently of the outcomes. Backend and explicit penalties are reused.- permutations
Number of random outcome permutations, at least one. The default 999 gives a minimum possible p-value of 0.001. Small values in examples illustrate usage only.
- inner.folds
Number of balanced, outcome-independent tuning folds. Used for the global test and within each outer training set.
- outer.folds
Number of outer folds for predictive assessment.
- seed
Nonnegative integer random seed. The caller's RNG state is restored. Realized folds, permutation seeds and RNG kind are returned.
- predictive
Whether to run nested CV in addition to the global test.
- warn
Warn if the observed fit, any permutation, or an outer fit fails.
- additional.tests
Character vector selecting optional permutation tests:
"absolute.deviation","total.variation", or both. Defaultcharacter()tests likelihood improvement only. Both curve summaries are always returned for the observed fit. Specify the tests before inspecting outcomes.- x
A
logistic.trend.filtering.assessmentto print.- ...
Reserved for generic compatibility.
Value
A logistic.trend.filtering.assessment list containing statistic,
p.value, p.value.bounds, status, null.probability, the newly tuned
observed fit, permutation statistics and diagnostic records, optional
nested-CV prediction, realized folds, seeds and solver settings.
curve.summaries is a named vector with absolute.deviation and
total.variation; curve.summary.details records their conventions and
any calculation failure. tests has one row per requested test, including
likelihood, with statistics, status, completed/failed permutation counts,
exceedances, comparison tolerances, raw p-values, lower/upper failure bounds
and p.value.holm. permutation.statistics contains a replicate column
and one column per tested statistic. The original permutations table
retains its likelihood-only schema.
prediction$scores contains model losses; prediction$improvement
contains baseline-minus-smoother gains; prediction$predictions and
prediction$diagnostics retain row-level and fold-level evidence.
Details
The null is a common unknown Bernoulli probability at all observed predictor locations. The constant estimate is the sample event rate, not a uniformly weighted integral over the continuous predictor domain. Independent observations must be exchangeable under this null. Repeated participants, serial dependence, confounding adjustment and grouped binomial counts require other null procedures and are not supported here. Independence cannot be established from a fitted object.
The input object's selected penalty and fold labels are not reused: those labels may depend on outcomes. A new outcome-independent fold assignment selects a penalty from the supplied path, including a full-data refit. Every permutation repeats this complete selection procedure on the same folds with the same solver settings. The statistic is the nonnegative part of twice the ordinary binomial log-likelihood improvement over the constant. It is not a penalized-objective difference and is not compared with a chi-squared distribution. Lambda order determines selection ties. Changing the path after inspecting the assessment invalidates the stated test unless that additional selection is included in the randomization.
Absolute deviation is mean(abs(p.hat(x) - mean(y))), evaluated at all
observed predictor locations, including repeats. It averages over sampled
observations, not uniformly over the predictor domain. A value of 0.04
means an average absolute departure of four percentage points. Total
variation is the sum of absolute probability changes along the fitted
curve over [min(x), max(x)]. It includes every knot and interior turning
point of the piecewise quadratic logit, up to floating-point precision;
it is not a coarse-grid approximation or the trend-filtering penalty.
For a monotone curve it equals the endpoint probability difference in
absolute value; an oscillating curve can have total variation above one.
These are descriptive summaries of the newly tuned fit, not uncertainty
intervals or bias-corrected population effect estimates.
Optional tests use the same selected fits, folds and permutations as the
likelihood test, with large values indicating departure from constancy.
No additional model fits or random draws are needed. Each statistic has
its own inclusive comparison tolerance and failure bounds. tests
reports individual p-values and Holm-adjusted p-values across likelihood
and the requested additional tests. Holm adjustment remains valid under
dependence; it does not adjust across other predictors or outcomes.
If any requested test is incomplete, all Holm values are unavailable.
Choosing the smallest unadjusted p-value after inspecting several tests
does not preserve the stated test level. The legacy scalar fields always
describe the unadjusted likelihood test, regardless of additional.tests.
Outcomes are shuffled uniformly with the predictor fixed, preserving the
total event count. With B successful permutations the Monte Carlo p-value
is (1 + sum(permuted.statistic >= observed.statistic))/(B + 1).
Under exchangeability this is a valid conditional randomization test,
subject to Monte Carlo discreteness. For numerical ties, comparisons allow
a conservative tolerance of 1e-10 * max(1, abs(observed.statistic)).
A failed candidate is ineligible under the fitter's usual CV rule. If no
candidate is eligible, that replicate fails. Failed replicates are never
dropped or retried: the point p-value is NA and p.value.bounds gives the
smallest/largest possible Monte Carlo p-value counting each missing
statistic as a nonexceedance/exceedance. These bounds are not a confidence
interval. An observed-fit failure leaves both bounds unavailable.
Predictive assessment uses separate outer folds. Each outer training set
inherits the input fit's cv.penalty.scale. Under "training_mass",
its lambda grid and ridge penalties are multiplied by the outer/full
sample-size ratio, and its inner folds apply their own training ratio.
Observed and permuted full-data refits use the same unscaled reference
grid. Older saved fits without this field retain "none" for reproduction.
Each outer training set
tunes the path using only its inner folds and predicts its outer test set.
The constant predictor is that outer training set's event rate. Both use
identical test observations. Pooled mean natural-log loss and Brier score
are reported; improvements are constant loss minus trend-filtering loss,
so positive values favor the smoother. These assess training on the outer
training-set size, not the full sample. No standard error is computed from
overlapping CV folds. Incomplete smoother predictions leave its overall
scores and improvements unavailable rather than scoring a selected subset.
Computation is sequential. A complete run uses approximately
(permutations + 1) * (inner.folds + 1) native path fits for the test,
plus outer.folds * (inner.folds + 1) for prediction. Per-replicate
diagnostics are retained, but full permuted fitted objects are not.
Rejecting constancy is evidence of association, not necessarily
nonlinearity, predictive usefulness or a causal effect.
References
Ojala and Garriga (2010). Permutation Tests for Studying Classifier Performance. https://www.jmlr.org/papers/v11/ojala10a.html
Phipson and Smyth (2010). Permutation p-values should never be zero. doi:10.2202/1544-6115.1585
Examples
x <- seq(0, 1, length.out = 60)
y <- rep(c(0, 1, 0, 1, 1), 12)
fit <- fit.logistic.trend.filtering(x, y, lambda = c(Inf, 0.01),
backend = "banded", curve.ridge = 0.1)
# Only nine permutations for a quick illustration; use more for inference.
assessment <- assess.logistic.trend.filtering(fit, permutations = 9,
inner.folds = 3, outer.folds = 3, seed = 42)
print(assessment)
#> Order-2 logistic trend-filtering assessment
#> Null: constant binary probability; independent, exchangeable observations
#> Global test: complete
#> Likelihood improvement statistic: 0.1334679
#> Permutation p-value: 0.9
#> Permutations: 9 of 9 completed
#> Observed probability-curve summaries:
#> absolute.deviation total.variation
#> 0.01987246 0.07807162
#> Nested-CV prediction: complete
#> model log.loss brier
#> Constant probability 0.6773568 0.2420833
#> Trend filtering 0.6809136 0.2437237
#> Improvement (constant minus smoother):
#> log.loss brier
#> -0.003556776 -0.001640347
assessment$prediction$improvement
#> log.loss brier
#> -0.003556776 -0.001640347
assessment$curve.summaries
#> absolute.deviation total.variation
#> 0.01987246 0.07807162
# Optional tests reuse the fits within an assessment run:
shape <- assess.logistic.trend.filtering(fit, permutations = 9,
inner.folds = 3, seed = 42, predictive = FALSE,
additional.tests = c("absolute.deviation", "total.variation"))
shape$tests
#> test statistic status requested completed failed exceedances
#> 1 likelihood 0.13346791 complete 9 9 0 8
#> 2 absolute.deviation 0.01987246 complete 9 9 0 8
#> 3 total.variation 0.07807162 complete 9 9 0 9
#> comparison.tolerance resolution p.value p.value.lower p.value.upper
#> 1 1e-10 0.1 0.9 0.9 0.9
#> 2 1e-10 0.1 0.9 0.9 0.9
#> 3 1e-10 0.1 1.0 1.0 1.0
#> p.value.holm
#> 1 1
#> 2 1
#> 3 1