Skip to content

Full support for shape-constrained PAMMs via scam (closes #286)#290

Closed
fabian-s wants to merge 2 commits into
adibender:masterfrom
fabian-s:claude/jolly-ride-okbteb
Closed

Full support for shape-constrained PAMMs via scam (closes #286)#290
fabian-s wants to merge 2 commits into
adibender:masterfrom
fabian-s:claude/jolly-ride-okbteb

Conversation

@fabian-s

Copy link
Copy Markdown
Collaborator

Closes #286.

Adds full support for shape-constrained additive models fit with scam::scam() across the entire pammtools post-processing workflow, with a new article showcasing the functionality.

What was broken

pammtools already had partial scam handling (make_X.scam, a few inherits(object, "scam") checks), but it was silently incorrect: for scam objects, coef() and $Vp are on the underlying unconstrained scale, while the lpmatrix returned by predict.scam(type = "lpmatrix") multiplies the re-parametrized (partially exponentiated) coefficient vector $coefficients.t, whose covariance is $Vp.t. So X %*% coef(object) produced wrong hazards (and wrong SEs) for any model with constrained terms.

Changes

  • New internal generics get_coefs(), get_Vp(), sample_coefs() (R/model-helpers.R) abstract the (X, coefs, V) triplet next to the existing make_X() generic. All consumers — add_hazard(), add_cumu_hazard(), add_surv_prob(), add_term(), add_cif(), add_trans_prob()/add_trans_ci(), get_cumu_coef(), get_cumu_eff(), compute_cumu_diff() — now go through them, which also removed the scattered is_gam branching and hard-coded predict.gam/$Vp calls. glm/gam/bam/pamm behavior is unchanged.

  • Confidence intervals: all three ci_types ("default", "delta", "sim") work for scam fits. They are based on the normal approximation for the re-parametrized coefficients ($coefficients.t, $Vp.t) — the same approximation underlying scam's own standard errors. (Sampling on the unconstrained scale and exponentiating per $p.ident would respect the constraints draw-by-draw, but is numerically unusable: coefficients shrunk to the constraint boundary have near-degenerate log-scale variances, so exp() of the draws overflows. Documented in the article.)

  • pamm() gains engine = "scam" (engine lookup now resolves gam/bam/scam to the proper namespaces instead of relying on attached packages).

  • tidy_fixed.scam and get_cumu_coef.scam methods; get_plotinfo() accepts scam objects, so tidy_smooth(), tidy_re() and the gg_* helpers work for scam fits; pec::predictSurvProb() works for pamm(engine = "scam") fits.

  • Class assertions in get_hazard()/get_cumu_hazard()/get_surv_prob() relaxed to accept scam objects (robust also for older scam versions whose objects did not inherit from glm).

  • New article vignettes/shape-constraints.Rmd ("Shape-constrained effects (scam)", registered in _pkgdown.yml): monotone-decreasing baseline hazard (bs = "mpd") vs. unconstrained fit, survival probabilities by group, monotone covariate effects (bs = "mpi"), pamm(engine = "scam"), and notes on CI computation.
    See attached.
    shapeconstraints.html

  • Tests (tests/testthat/test-scam.R, 67 assertions): hazard/SE correctness against predict.scam(se.fit = TRUE), monotonicity of constrained fits, all CI types for hazard/cumulative hazard/survival probability, grouped cumulative hazards, add_term() with reference, CIF with constrained by-cause smooths, cumulative coefficients, pamm(engine = "scam"), predictSurvProb, tidiers and plotting.

Local verification: full test suite passes (the only 2 failures are pre-existing environment quirks in test-warnings.R unrelated to this change, failing identically on master), R CMD check clean apart from pre-existing NOTEs, article renders in ~9s.

https://claude.ai/code/session_011bPCsxyWjbK9TzWA9M7ceH

claude added 2 commits June 10, 2026 15:42
Centralize model-class handling in three internal generics
(get_coefs, get_Vp, sample_coefs in R/model-helpers.R) and use them
together with the existing make_X generic throughout the
post-processing workflow (add_hazard, add_cumu_hazard, add_surv_prob,
add_term, add_cif, add_trans_prob, get_cumu_coef, get_cumu_eff,
compute_cumu_diff).

For scam fits this fixes the previously incorrect use of the
unconstrained-scale coefficients/covariance (coef()/$Vp): predictions
and all three CI types (default, delta, sim) are now based on the
re-parametrized coefficients ($coefficients.t) and their covariance
($Vp.t), matching predict.scam(se.fit = TRUE). Simulation-based CIs
draw from the corresponding normal approximation, the same one
underlying scam's own standard errors (the exact posterior of the
constrained coefficients is not Gaussian; sampling on the unconstrained
scale is numerically unusable because coefficients shrunk to the
constraint boundary have near-degenerate log-scale variances).

Also:
* pamm() gains engine = "scam"
* tidy_fixed.scam, get_cumu_coef.scam methods; get_plotinfo accepts
  scam objects (tidy_smooth, tidy_re, gg_* work for scam fits)
* relax get_hazard/get_cumu_hazard/get_surv_prob class assertions to
  accept scam
* new article vignettes/shape-constraints.Rmd showcasing monotone
  baseline hazards and covariate effects, registered in _pkgdown.yml
* tests: tests/testthat/test-scam.R covering hazard/se correctness
  against predict.scam, monotonicity, all CI types, grouped cumulative
  hazards, add_term, CIF, cumulative coefficients, pamm engine,
  predictSurvProb, tidiers and plots

https://claude.ai/code/session_011bPCsxyWjbK9TzWA9M7ceH
Copilot AI review requested due to automatic review settings June 10, 2026 15:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends pammtools’ post-processing/prediction workflow to correctly support shape-constrained additive models fit with scam::scam(), ensuring hazards/SEs/CIs are computed on the re-parameterized coefficient scale used by predict.scam(type = "lpmatrix").

Changes:

  • Introduces internal helpers (get_coefs(), get_Vp(), sample_coefs()) and routes downstream computations through the consistent (X, coefs, V) triplet to fix previously silent scale mismatches for scam.
  • Adds pamm(engine = "scam"), plus tidy_fixed.scam, get_cumu_coef.scam, and extends plotting/tidying support via get_plotinfo() accepting scam objects.
  • Adds a new vignette (shape-constraints) and a comprehensive test-scam.R suite covering hazard/SE correctness, monotonicity, CI types, CIF, cumulative effects, and pec::predictSurvProb() compatibility.

Reviewed changes

Copilot reviewed 11 out of 21 changed files in this pull request and generated no comments.

Show a summary per file
File Description
vignettes/shape-constraints.Rmd New article demonstrating monotone baseline/covariate effects with scam and notes on CI computation.
tests/testthat/test-scam.R New test coverage validating correctness vs predict.scam(), monotonicity, CI modes, CIF, tidiers, plotting, and pamm(engine="scam").
R/tidiers.R Adds tidy_fixed.scam; updates get_plotinfo() to accept scam objects for tidiers/plot helpers.
R/pammfit.R Adds engine = "scam" and resolves engine functions via namespaces (mgcv/scam).
R/model-helpers.R New internal generics for coefficient/covariance extraction and coefficient simulation, enabling correct scam handling.
R/cumulative-effect.R Switches cumulative effect computations to get_coefs()/get_Vp()/make_X().
R/cumulative-coefficient.R Adds get_cumu_coef.scam and routes simulation/point estimates through the new helpers.
R/add-functions.R Refactors hazard/CI/CIF/transition-CI code paths to use get_coefs()/get_Vp()/sample_coefs() and expands class acceptance to scam.
NEWS.md Documents the new full scam support and links the new article.
NAMESPACE Registers new S3 methods and updates imports.
man/*.Rd Updates/creates documentation entries for the new methods/helpers and updated behavior.
_pkgdown.yml Registers the new vignette in articles and navbar.
Files not reviewed (10)
  • man/add_hazard.Rd: Language not supported
  • man/add_term.Rd: Language not supported
  • man/compute_cumu_diff.Rd: Language not supported
  • man/cumulative_coefficient.Rd: Language not supported
  • man/get_Vp.Rd: Language not supported
  • man/get_coefs.Rd: Language not supported
  • man/get_plotinfo.Rd: Language not supported
  • man/pamm.Rd: Language not supported
  • man/sample_coefs.Rd: Language not supported
  • man/tidy_fixed.Rd: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread R/model-helpers.R

@johannespiller johannespiller Jun 15, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can consolidate helpers.R and model-helpers.R? Or was this a conscientous choice?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

conscientious? maybe.
conscious? not sure - is claude conscious...? ;)
seems fine to me to leave these in their own file separate from the other helpers IMO

@johannespiller johannespiller Jun 15, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright. Fine for me. conscious* Difficult word.

@fabian-s

Copy link
Copy Markdown
Collaborator Author

see #292

@fabian-s fabian-s closed this Jun 15, 2026
fabian-s added a commit that referenced this pull request Jun 17, 2026
Consolidated PRs #284, #287, #289, #290, #291 and consistent t=0 boundary rows, shared simulation draws, and S3 dispatch fixes for `add_*` functions
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

scam extension?

4 participants