TemporalHazard 1.0.3
Bug fixes / CRAN compliance
hzr_bootstrap() no longer touches
.GlobalEnv directly. The 1.0.2
oldseed/on.exit()/assign(".Random.seed", ...)
save-restore wrapper added in 1.0.2 violated CRAN policy on writing to
.GlobalEnv and has been removed. When seed is
supplied the function simply calls set.seed(seed) (the
documented R API for seeded reproducibility); the
@param seed documentation now notes that the caller’s RNG
state is not restored on exit. With seed = NULL (the
default) the function does not call set.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(), previously
R/golden_fixtures.R) have been moved out of the package to
data-raw/golden_fixtures.R. They are maintainer-only
helpers for regenerating the bundled inst/fixtures/*.rds
reference 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 to
system.file("fixtures", ...) — i.e. the installed package
directory — whenever the package was installed, so the 1.0.1 “falls back
to tempdir()” fix did not actually prevent writing to the
user library. The bundled .rds fixtures still ship and the
parity tests still read them via system.file().
.hzr_generate_golden_fixture() (the C-binary reference
writer in R/parity-helpers.R, which shares a file with
test-time helpers and so was kept in the package) now takes a required
output_dir argument with no default path.
- Removed the remaining hardcoded
seed = 42 literals from
the relocated generators; recorded fixture metadata reflects the actual
seed argument passed (NULL by default, so no
seed is set inside the function).
hzr_bootstrap() no longer leaves the caller’s
random-number stream altered when seed is supplied: the
global .Random.seed is saved before set.seed()
and restored via on.exit(), matching the fixture
generators. Bootstrap reproducibility under a given seed is
unchanged.
TemporalHazard 1.0.1
Bug fixes / CRAN compliance
- Added
\value documentation to all exported functions
that were missing it: hazard(), coef.hazard(),
vcov.hazard(), print.hzr_calibrate(),
print.hzr_deciles(), print.hzr_gof(), and
print.hzr_kaplan().
- Internal fixture generators (
R/golden_fixtures.R) no
longer set a specific seed unconditionally. Generators now accept an
optional seed argument; when provided, the global RNG state
is saved and restored via on.exit().
- Default
output_dir for fixture generators falls back to
tempdir() 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 = FALSE and
level = 0.95. When se.fit = TRUE, the return
value becomes a data frame with columns fit,
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 to numDeriv::jacobian on a per-call cumhaz
closure.
- Transforms match SAS HAZARD
(
hzp_calc_haz_CL.c / hzp_calc_srv_CL.c):
hazard and cumulative_hazard use log-scale
CLs; survival uses log(-log S) CLs (equivalent to
log-cumhaz) so 0 <= lower <= upper <= 1;
linear_predictor is 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.
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 any start > 0
is now accepted. The Weibull and multiphase log-likelihoods apply
H(stop) - H(start) to event and right-censored terms; the
trivial start = 0 case degenerates to H(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 theta term per row (guarded at
start = 0). The multiphase analytic gradient computes
per-phase Phi_j(start) and its shape derivatives, then adds
+w_H_start * mu_j * dPhi_j(start) to each parameter’s
score; G3 phase derivatives at start use the same
finite-difference machinery as at stop.
- 0.9.5 narrowing removed. The
hazard()
guard that rejected counting-process
Surv(start, stop, event) with any start > 0
is gone.
TemporalHazard 0.9.6
New features
weights now 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 in
hazard() that rejected weights for
dist %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 optional
weights argument; 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 neither weights nor its downstream equivalents:
the per-row score weights w_H / inv_h were 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’s
gradient_fn wrapper (including the all-zero numeric
fallback and the CoE wrapper) forwards weights
consistently. 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 existing hazard fit 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 SAS PROC HAZARD
(SLENTRY = 0.30, SLSTAY = 0.20); AIC mode uses
ΔAIC < 0 uniformly. SAS-style MOVE
oscillation guard freezes variables that enter + exit more than
max_move times. Returns an object of class
c("hzr_stepwise", "hazard") with a $steps
selection trace, scope record, and elapsed timer. Implements the core
algorithm from C HAZARD stepw.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
weights
threading (dup-arg collision in the multiphase / Weibull closures,
positional-arg corruption in every distribution’s gradient call) made
every optimizer iteration error silently inside tryCatch.
Diagnosed and fixed via commit 73b4657.
- Weibull analytic gradient now applies
weights — both
.hzr_gradient_weibull() and the grad_internal
closure inside .hzr_optim_weibull() accepted
weights as 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
weights is now only accepted for
dist = "weibull" and dist = "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 when
weights is supplied with one of those distributions rather
than returning an unweighted fit. Full support for the remaining
single-dist paths is tracked in
inst/dev/DEVELOPMENT-PLAN.md Phase 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 in inst/dev/DEVELOPMENT-PLAN.md
Phase 4e.
- Repeating-events / counting-process notation
narrowed.
Surv(start, stop, event) with
start > 0 is no longer accepted by
hazard(). The 0.9.4 NEWS claimed each epoch contributed
H(stop) - H(start) to the likelihood, but downstream
likelihoods only read time_lower for interval-censored rows
(status == 2); counting-process rows (status
in {0, 1}) were silently scored with H(stop)
alone, so any fit with nonzero entry times was silently wrong.
hazard() now raises an explicit error. The trivial case
Surv(0, t, d) – equivalent to Surv(t, d) –
continues to work. Full wire-up of H(stop) - H(start) for
all distribution paths is tracked in
inst/dev/DEVELOPMENT-PLAN.md Phase 4f.
TemporalHazard 0.9.4
New features
- Observation weights —
weights argument
in hazard() applies Fisher weighting to the log-likelihood
for dist = "weibull" and dist = "multiphase".
Each observation’s contribution is multiplied by its weight, enabling
severity-weighted event analyses. Implements the SAS WEIGHT
statement. 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 contributed
H(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 trivial start = 0
case 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 SAS
deciles.hazard.sas macro workflow.
hzr_gof() — Goodness-of-fit function comparing
parametric predictions against nonparametric (Kaplan-Meier) estimates
with observed vs. expected event counting. Implements the SAS
hazplot.sas macro 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 SAS kaplan.sas macro 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 the by parameter.
Implements the SAS logit.sas and logitgr.sas
macros.
hzr_nelson() — Wayne Nelson cumulative hazard estimator
with lognormal confidence limits. Supports weighted events for
severity-adjusted repeated event analyses. Implements the SAS
nelsonl.sas macro.
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 SAS bootstrap.hazard.sas macro
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 SAS
markov.sas macro.
- 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 HAZARD setcoe.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.
fit parameter 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 in hzr_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 via na.strings = c("NA", ".") in
data-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_pkgload for
lazy data compatibility.
- Added lintr CI workflow with
.lintr configuration.
- pkgdown action bumped to
peaceiris/actions-gh-pages@v4.
- Added
use-public-rspm: true to all CI workflows.
- Added
lintr to Suggests.
TemporalHazard 0.9.0
New features
- Multiphase engine: N-phase additive cumulative hazard models via
dist = "multiphase" with hzr_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 with predict(),
summary(), coef(), vcov() S3
methods.
- Golden fixture regression testing system.
- Numerically stable helper primitives (
hzr_log1pexp,
hzr_log1mexp, hzr_clamp_prob).
TemporalHazard 0.0.0.9000
- Initial package scaffold.
- Added numerically stable helper primitives.
- Added baseline unit tests and CI workflow.