Repository navigation
-
hzr_deciles()ranked a multiphasetime_windowsfit by the wrong
window's coefficients (#629). For the horizon ranking it read each
subject's stored design, whichtime_windowshad expanded at that
subject's exit time, so a subject who exited in one window was ranked
with that window's coefficient even when the horizon falls in another.
On two 400-subject examples, 12 and 85 subjects landed in the wrong risk
group, andmean_survivalwas wrong in every group, with no warning. The horizon
design is now built at the horizon throughpredict(), ashzr_gof()
and the single-distribution path already do. A caller'sevent_timeis
handled the same way: the design is expanded atevent_timewhenever it
differs from the stored times, for H(event_time) and, on a
left-truncated fit, for the H(entry) subtracted from it, so the two use
the same window. Expected events at the defaultevent_time, each
subject's own exit time, are unchanged. -
On a multiphase
time_windowsfit saved by 1.2.9 or earlier,
predict(newdata = )andhzr_gof()could swap a phase formula's own
covariates for the global ones (#658). Such a fit has no record of which
phases took the global design, so it was read from the stored design's
column names. A phase formula can use columns named like the
window-expanded global ones (x1_w1,x1_w2) that hold other covariates,
and that phase was read as inheriting.predict(newdata = )was then off
by up to 77% relative in one example, andhzr_gof()'s curve moved, with
no warning. A phase is now read as inheriting only when its stored design
equals the global design, expanded at the stored times, in values as well
as names. Fits saved with the record, and every fit made by a current
version, are unchanged. -
hzr_deciles()miscounted expected events when a caller'sevent_time
disagreed with a row'stime_lower(#656). Both cases were silent.
Anevent_timeat or below a left-truncated row's entry dropped the
entry correction, H(entry), so the row counted H(event_time) expected
events where none are defined; that is now an error naming the first such
row. And a row withtime_lowerequal to its stored time, which the
likelihood reads as having no entry, was read as truncated once
event_timewas later than that time, losing H(time). Truncation is now
decided as the likelihood decides it: status 0 or 1 with
0 < time_lower < timeat the stored time. Calls that leaveevent_time
at its default, andhzr_gof(), are unchanged. -
hzr_bootstrap()pooled replicates with no finite maximum (#654). A
resample with separation, such as no events at one level of a factor, has
a likelihood that keeps rising as a coefficient, the intercept or a
phase'slog_muruns to infinity. The refit stops where the slope falls
below the optimizer's tolerance and reports convergence with a small
gradient, so it passed every check and its estimate was pooled. In one
example 12 of 40 replicates ran out to between -7 and -15 against -1.4 on
the full data, and the coefficient's bootstrap sd was 5.0 where the other
28 give 0.51, with no warning. Each replicate is now tested by stepping
further out from its estimate: along each coefficient, and along the
direction its standard errors, or failing those its Hessian, say is
flattest, which is the one a separation along a combination of
parameters takes. When the log-likelihood does not fall, the replicate
fails with the reason
"likelihood flat or still rising (no unique finite maximum)", it leaves
the summary, and a warning gives the count. A replicate whose
design is rank-deficient, such as a factor level absent from the resample
or a column that is an exact combination of others, is dropped the same
way: its estimates are not determined by the data. The fit being
bootstrapped is tested the same way first, and warned about if it fails,
as a multiphase phase with covariates but few events of its own can. The
step is sized on the whole linear predictor, intercept included, and the
tolerance scales with the mean weight, so a covariate far from zero or
very small weights do not make a genuine maximum read as flat.
The warning also says what the summary is now conditional on: only the
resamples in which the model is identified, which understates the
uncertainty and moves the other parameters' intervals too. Onavcwith
a constant phase carryingmal, 17 of 30 replicates were dropped and the
constant.malinterval narrowed from about [-19, 12] to [-0.1, 1.8].
When 20% or more of the replicates are dropped, the warning says to treat
the summary as unreliable. -
A Conservation of Events fit could report wrong standard errors when its
full-information variance could not be computed (#652). The variance from
the search holds the conserved phase'slog_mufixed, so it treats that
parameter as known, and it was taken at the starting value oflog_mu
rather than the solved one. When the full-information Hessian could not be
computed or inverted, the fit fell back to that variance and reported a
standard error for every other parameter, while the warning named only the
conservedlog_mu. Onavcwith two phases, one standard error was 0.17
of its full-information value and another 1.3 times it. Such a fit now
reports no standard errors, warns that none are reported, and records why
indegraded_causes;vcov()returnsNA. The estimates are unchanged.
The conservedlog_muis also now counted as estimated, as it is when the
recompute succeeds, so the fit's AIC no longer comes out 2 lower than the
same fit's with a successful recompute. -
Behaviour change:
hzr_bootstrap(seed = )now sets the session's random
number stream, asset.seed()does, and no longer restores it on exit (#653). Restoring the
caller's stream (#611) meant writing.Random.seedinto the global
environment, which CRAN policy does not allow. The replicates for a given
seed are unchanged. What changes is the stream after the call: it continues
from where the bootstrap's draws left it, so a script that seeded once at
the top and draws after a seeded bootstrap now gets different numbers from
those draws. Save.Random.seedbefore the call and restore it after, or use
withr::with_preserve_seed(), to keep your own stream.withrmoves from
Imports to Suggests. -
A
.inside a function call in a formula was dropped without a word.
terms()writes out.only where it is a term of its own, so
Surv(time, status) ~ log(abs(.))reached the design as~ 1and the
model was fitted with no covariates. The same held for a phase's
hzr_phase(formula = ). Beside a bare., as in~ . + log(.),terms()
substituted the sum of the columns, giving one covariatelog(x1 + x2).
hazard()now stops on.anywhere but as a term of the formula
operators, naming the term, aslm()stops on these formulas.~ .,
~ . - age,~ (.)^2and~ .:ageare unchanged. -
A formula helper that reads an outside vector by position is now refused
when rows at time 0 are dropped (#590).hazard()drops a row at time 0
before fitting, and builds the design on the rows that remain. A helper
such asfunction(a) a + g[seq_along(a)], withgaligned to every row
given, then paired the remaining rows with the first values ofg, with
no warning. In one example all 48 of 48 rows were paired with the wrong
value; in another, an alternating treatment arm read this way fitted its
coefficient with the sign reversed. The existing check reads only the
variables the formula names, so it could not seeginside the function.
hazard()now also evaluates the formula's variables on every row in
order and again with the remaining rows first, as the fit sees them, and
refuses a variable that then gives a remaining row a value other than its
own, naming it. Terms computed from the rows as a set, such asscale(),
poly(),ns()and factors, pass and still use the remaining rows. A
term that depends on the order of the rows, such ascumsum(age), or is
random, such asjitter(age), is now refused when rows other than the
last are dropped, where it was fitted before. A helper that depends on
how many rows it is given, such astail(g, length(a))or
a * mean(g[seq_along(a)]), is not caught. Put such a vector indata,
where it is dropped with its rows. -
hzr_bootstrap(id =)resamples patients, not rows (#667). Data with
several rows per patient, such as time-varying covariates in
counting-process form (Surv(start, stop, event)ortime_lower =), were
resampled row by row, so a replicate could hold some of a patient's
segments and not others, or one of them twice.idnames the patient,
as a column ofdataor a vector with one value per row; each replicate
then draws patients with replacement and keeps every row of each one
drawn, andfractioncounts patients. This is SAS%HAZBOOTwith
_TVC=1, _IDVAR=. The default,id = NULL, resamples rows as before, and
the sameseedgives the same replicates as before. A fit with entry
times and noidnow draws a warning that its rows may not be patients.