Changelog
Source:NEWS.md
TemporalHazard 1.0.3
CRAN release: 2026-05-30
Bug fixes / CRAN compliance
-
hzr_bootstrap()no longer touches.GlobalEnvdirectly. The 1.0.2oldseed/on.exit()/assign(".Random.seed", ...)save-restore wrapper added in 1.0.2 violated CRAN policy on writing to.GlobalEnvand has been removed. Whenseedis supplied the function simply callsset.seed(seed)(the documented R API for seeded reproducibility); the@param seeddocumentation now notes that the caller’s RNG state is not restored on exit. Withseed = NULL(the default) the function does not callset.seed()at entry, so it starts from the caller’s current RNG state; the bootstrap still consumes random numbers and advances that state in the usual way.
TemporalHazard 1.0.2
Bug fixes / CRAN compliance
- The golden-fixture generators (
.hzr_create_*_golden_fixture(), previouslyR/golden_fixtures.R) have been moved out of the package todata-raw/golden_fixtures.R. They are maintainer-only helpers for regenerating the bundledinst/fixtures/*.rdsreference outputs and are not part of the installed package, so they are no longer shipped, checked, or user-reachable. This resolves the home-filespace concern at its root: the earlier fallback resolved tosystem.file("fixtures", ...)— i.e. the installed package directory — whenever the package was installed, so the 1.0.1 “falls back totempdir()” fix did not actually prevent writing to the user library. The bundled.rdsfixtures still ship and the parity tests still read them viasystem.file(). -
.hzr_generate_golden_fixture()(the C-binary reference writer inR/parity-helpers.R, which shares a file with test-time helpers and so was kept in the package) now takes a requiredoutput_dirargument with no default path. - Removed the remaining hardcoded
seed = 42literals from the relocated generators; recorded fixture metadata reflects the actualseedargument passed (NULLby default, so no seed is set inside the function). -
hzr_bootstrap()no longer leaves the caller’s random-number stream altered whenseedis supplied: the global.Random.seedis saved beforeset.seed()and restored viaon.exit(), matching the fixture generators. Bootstrap reproducibility under a givenseedis unchanged.
TemporalHazard 1.0.1
Bug fixes / CRAN compliance
- Added
\valuedocumentation to all exported functions that were missing it:hazard(),coef.hazard(),vcov.hazard(),print.hzr_calibrate(),print.hzr_deciles(),print.hzr_gof(), andprint.hzr_kaplan(). - Internal fixture generators (
R/golden_fixtures.R) no longer set a specific seed unconditionally. Generators now accept an optionalseedargument; when provided, the global RNG state is saved and restored viaon.exit(). - Default
output_dirfor fixture generators falls back totempdir()instead of the package source directory, keeping the home filespace unmodified.
TemporalHazard 0.9.8
New features
-
Delta-method confidence limits on
predict.hazard()— Phase 4g of the development plan lands. Two new arguments:se.fit = FALSEandlevel = 0.95. Whense.fit = TRUE, the return value becomes a data frame with columnsfit,se.fit,lower,upper.-
Weibull and multiphase use closed-form Jacobians (
dH/dtheta,dexp(eta)/dtheta,deta/dtheta); exponential / log-logistic / log-normal fall back tonumDeriv::jacobianon a per-call cumhaz closure. -
Transforms match SAS HAZARD (
hzp_calc_haz_CL.c/hzp_calc_srv_CL.c):hazardandcumulative_hazarduse log-scale CLs;survivaluses log(-log S) CLs (equivalent to log-cumhaz) so 0 <= lower <= upper <= 1;linear_predictoris symmetric on the natural scale. -
Fixed-shape / CoE multiphase fits produce meaningful CLs — the delta-method sandwich is restricted to the free-parameter submatrix of
vcov, treating fixed parameters as known-with-zero-variance. - Backward compatible:
se.fit = FALSE(default) preserves the pre-0.9.8 scalar-vector / decompose-data-frame return shape.
-
Weibull and multiphase use closed-form Jacobians (
TemporalHazard 0.9.7
New features
-
Counting-process / repeating-events likelihood wired up — Phase 4f of the development plan lands.
Surv(start, stop, event)with anystart > 0is now accepted. The Weibull and multiphase log-likelihoods applyH(stop) - H(start)to event and right-censored terms; the trivialstart = 0case degenerates toH(stop)and recovers the plain-Surv fit exactly. Splitting each row into contiguous epochs preserves both the log-likelihood and the MLE to optimizer tolerance (split-invariance). -
Weibull + multiphase analytic gradients handle H(start). The closed-form Weibull score adds a
-d H(start)/d thetaterm per row (guarded atstart = 0). The multiphase analytic gradient computes per-phasePhi_j(start)and its shape derivatives, then adds+w_H_start * mu_j * dPhi_j(start)to each parameter’s score; G3 phase derivatives atstartuse the same finite-difference machinery as atstop. -
0.9.5 narrowing removed. The
hazard()guard that rejected counting-processSurv(start, stop, event)with anystart > 0is gone.
TemporalHazard 0.9.6
New features
-
weightsnow supported for all distributions — Phase 4e of the development plan lands. The exponential, log-logistic, and log-normal likelihoods and their analytic gradients now apply row weights to every censoring term (event, right-censored, left-censored, interval-censored). The 0.9.5 guard inhazard()that rejectedweightsfordist %in% c("exponential", "loglogistic", "lognormal")has been removed. Fits with integer weights reproduce the row-duplicated fit to optimizer tolerance across all five distributions. -
Conservation of Events now honours weights.
.hzr_conserve_events()and.hzr_select_fixmu_phase()take an optionalweightsargument; the multiphase optimizer threads it through so per-phase cumulative hazards are summed on the same scale as the (weighted) observed event count. CoE no longer auto-disables when weights are non-uniform — the dimension reduction stays on and the MLE matches the full-dim path.
Bug fixes
-
Multiphase analytic gradient now applies
weights..hzr_gradient_multiphase()accepted neitherweightsnor its downstream equivalents: the per-row score weightsw_H/inv_hwere set to ±1 and the interval-censored finite-difference correction summed an unweighted LL. Weighted multiphase fits therefore optimised a weighted objective with an unweighted score; BFGS line search still converged near the correct MLE but the final gradient norm did not go to zero. All three paths now honour row weights, and the optimizer’sgradient_fnwrapper (including the all-zero numeric fallback and the CoE wrapper) forwardsweightsconsistently. Regression test covers weighted analytic vs numerical gradient parity. Surfaced by Copilot review on PR #18.
TemporalHazard 0.9.5
New features
-
Stepwise covariate selection —
hzr_stepwise()runs forward, backward, or two-way stepwise selection on an existinghazardfit using Wald p-values or AIC deltas as the entry / retention criterion. Phase-specific entry is supported for multiphase models: a covariate can enter one phase and not another. Defaults match SASPROC HAZARD(SLENTRY = 0.30,SLSTAY = 0.20); AIC mode usesΔAIC < 0uniformly. SAS-styleMOVEoscillation guard freezes variables that enter + exit more thanmax_movetimes. Returns an object of classc("hzr_stepwise", "hazard")with a$stepsselection trace, scope record, and elapsed timer. Implements the core algorithm from C HAZARDstepw.c/backw.c.
Bug fixes
-
Multiphase convergence after weights/repeating-events merge — restored multiphase optimization that regressed in 0.9.4: three interacting defects in the new
weightsthreading (dup-arg collision in the multiphase / Weibull closures, positional-arg corruption in every distribution’s gradient call) made every optimizer iteration error silently insidetryCatch. Diagnosed and fixed via commit 73b4657. -
Weibull analytic gradient now applies
weights— both.hzr_gradient_weibull()and thegrad_internalclosure inside.hzr_optim_weibull()acceptedweightsas a formal but did not apply it to the score vector. The optimizer still converged via line search on the (weighted) log-likelihood, but the gradient direction was wrong and the final gradient norm did not go to zero. Both gradient paths now weight the event indicator and cumulative hazard building blocks. Fits with integer weights reproduce the equivalent row-duplicated fit to optimizer tolerance.
Scope change
-
weightsis now only accepted fordist = "weibull"anddist = "multiphase". The 0.9.4 NEWS claimed weights were threaded through all distribution-specific likelihoods; in fact the exponential, log-logistic, and log-normal single-distribution paths accepted the formal but never applied it, so the fit was silently unweighted.hazard()now raises an explicit error whenweightsis supplied with one of those distributions rather than returning an unweighted fit. Full support for the remaining single-dist paths is tracked ininst/dev/DEVELOPMENT-PLAN.mdPhase 4e. -
Conservation of Events is auto-disabled when weights are not all 1.
.hzr_conserve_events()receives the weighted event count as its target but sums per-phase cumulative hazards across rows without applying weights, so Turner’s adjustment comes out on a mismatched scale. The multiphase optimizer now detects non-unit weights and skips the CoE dimension reduction, falling through to the (correctly weighted) full-dimensional path. Fits are still correct; they just don’t benefit from the one-parameter analytical closed-form solve. Weighted CoE wire-up is tracked alongside the other weights completion work ininst/dev/DEVELOPMENT-PLAN.mdPhase 4e. -
Repeating-events / counting-process notation narrowed.
Surv(start, stop, event)withstart > 0is no longer accepted byhazard(). The 0.9.4 NEWS claimed each epoch contributedH(stop) - H(start)to the likelihood, but downstream likelihoods only readtime_lowerfor interval-censored rows (status == 2); counting-process rows (statusin{0, 1}) were silently scored withH(stop)alone, so any fit with nonzero entry times was silently wrong.hazard()now raises an explicit error. The trivial caseSurv(0, t, d)– equivalent toSurv(t, d)– continues to work. Full wire-up ofH(stop) - H(start)for all distribution paths is tracked ininst/dev/DEVELOPMENT-PLAN.mdPhase 4f.
TemporalHazard 0.9.4
New features
-
Observation weights —
weightsargument inhazard()applies Fisher weighting to the log-likelihood fordist = "weibull"anddist = "multiphase". Each observation’s contribution is multiplied by its weight, enabling severity-weighted event analyses. Implements the SASWEIGHTstatement. The original 0.9.4 entry claimed coverage of all distribution paths; the 0.9.5 patch corrected the claim and fixed a gradient wire-up bug in the Weibull path. -
Repeating events —
Surv(start, stop, event)start-stop notation is parsed. The original 0.9.4 entry claimed each epoch contributedH(stop) - H(start)to the likelihood, but the downstream likelihoods never applied the lower bound for counting-process rows; the 0.9.5 patch narrowed the feature to the trivialstart = 0case and added an explicit error for nonzero starts.
TemporalHazard 0.9.3
New features
-
hzr_deciles()— Decile-of-risk calibration function comparing observed vs. expected event counts across risk groups with chi-square GOF testing. Implements the SASdeciles.hazard.sasmacro workflow. -
hzr_gof()— Goodness-of-fit function comparing parametric predictions against nonparametric (Kaplan-Meier) estimates with observed vs. expected event counting. Implements the SAShazplot.sasmacro workflow. -
hzr_kaplan()— Kaplan-Meier survival estimator with logit-transformed confidence limits that respect the [0, 1] boundary, interval hazard rate, density, and restricted mean survival time (life integral). Implements the SASkaplan.sasmacro output structure. -
hzr_calibrate()— Variable calibration function for assessing functional form before model entry. Groups a continuous covariate into quantile bins and applies logit, Gompertz, or Cox link transforms. Supports stratification via thebyparameter. Implements the SASlogit.sasandlogitgr.sasmacros. -
hzr_nelson()— Wayne Nelson cumulative hazard estimator with lognormal confidence limits. Supports weighted events for severity-adjusted repeated event analyses. Implements the SASnelsonl.sasmacro. -
hzr_bootstrap()— Bootstrap resampling for hazard model coefficients with bagging support (fractional sampling). Returns per-replicate estimates and summary statistics (mean, SD, percentile CI). Implements the SASbootstrap.hazard.sasmacro workflow. -
hzr_competing_risks()— Competing risks cumulative incidence using the Aalen-Johansen estimator with Greenwood variance. Handles any number of competing event types. Implements the SASmarkov.sasmacro. -
Conservation of Events (CoE) — Turner’s theorem is now integrated into the multiphase optimizer. One phase’s log_mu scaling parameter is solved analytically at each iteration, reducing the optimization dimension by 1 and improving numerical stability and convergence. Enabled by default; disable with
control = list(conserve = FALSE). Implements the core algorithm from C HAZARDsetcoe.c/consrv.c. - New vignette: “Complete Clinical Analysis Walkthrough” — end-to-end workflow from Kaplan-Meier baseline through validated multivariable model, mirroring the SAS HAZARD analytical sequence.
Improvements
- Multi-start optimizer now respects user-set RNG seeds for reproducibility (removed
set.seed(NULL)that was actively breaking determinism). - Vignette metadata normalized to YAML
vignette:key across all 8 files. -
fitparameter documentation corrected to state default is FALSE. - README now includes key capabilities table and development plan link.
TemporalHazard 0.9.1
New features
- G3 late-phase decomposition (
hzr_phase("g3", ...)) now fully integrated into the multiphase optimizer, Hessian, and prediction pipeline. -
fixed = "shapes"parameter inhzr_phase()allows fixing shape parameters during estimation (matching C/SAS HAZARD workflow of estimating only log-mu scale parameters).
Bug fixes
-
summary.hazard()now correctly reports standard errors when some parameters are fixed. Previously,anyNA(vcov)rejected the entire variance-covariance matrix when fixed parameters had NA entries. -
print.summary.hazard()coefficient table now shows the correct label for G3 phases (was printing empty parentheses). -
print.summary.hazard()phase listing now uses the phase name in CDF labels (e.g., “cdf (late risk)”) instead of hardcoded “early risk”. - SAS missing value markers (
.) in CSV datasets are now handled viana.strings = c("NA", ".")indata-raw/make_data.R, preventing numeric columns from being read as character.
Documentation
- Seven Quarto vignettes: getting-started, fitting-hazard-models, prediction-visualization, inference-diagnostics, mathematical-foundations, package-architecture, and sas-to-r-migration.
- Roxygen examples now include both single-phase and multiphase models.
- README switched to self-contained CABGKUL examples with G3 late phase.
- Dataset axis labels corrected to “Months” (not “Years”).
Infrastructure
- CI workflows updated to use
roxygen2::load_pkgloadfor lazy data compatibility. - Added lintr CI workflow with
.lintrconfiguration. - pkgdown action bumped to
peaceiris/actions-gh-pages@v4. - Added
use-public-rspm: trueto all CI workflows. - Added
lintrto Suggests.
TemporalHazard 0.9.0
New features
- Multiphase engine: N-phase additive cumulative hazard models via
dist = "multiphase"withhzr_phase()specification. -
hzr_decompos()parametric family implementing the three-parameter temporal decomposition of Blackstone, Naftel, and Turner (1986). - Multi-start optimizer with Hessian-based variance-covariance estimation.
- C binary parity tests against the KUL CABG reference dataset.
- Five clinical reference datasets:
avc,cabgkul,omc,tga,valves.
TemporalHazard 0.1.0
New features
- Single-phase engine: Weibull, exponential, log-logistic, and log-normal distributions with formula interface.
-
hazard()API withpredict(),summary(),coef(),vcov()S3 methods. - Golden fixture regression testing system.
- Numerically stable helper primitives (
hzr_log1pexp,hzr_log1mexp,hzr_clamp_prob).