The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
doFuture and doRNG
dependencies.log() of a non-positive value), naming the term,
instead of NROW(y) == nrow(x) is not TRUE. Such rows were
silently dropped from the model matrix, despite
na.action = na.pass, which model.matrix()
ignores.Trial-periods (Eligible) count
including trial-periods that start too late to reach the window before
the data end, which also inflated Censored and
% Censored. Estimates are unchanged.deviation.excused_cols excusing deviations in every
arm; column i now excuses only deviations by people following
treat.level[[i]]. Deviation analyses are currently
disabled, so no results change.excused.cols the opposite way
to the weight models. Column i now excuses a switch away from
treat.level[[i]] throughout
(e.g. excusedZero = 1 excuses a switch from 0 to 1), which
changes every excused = TRUE analysis.weight.upper = 1 truncation.treat.level, making estimates depend on that
order. This shifts pre-expansion weighted estimates, most for excused
censoring.subgroup are unchanged.treat.level and, for post-expansion weights, were wrong by
default (only the first arm was converted to the probability of
remaining uncensored).SEQuential() now restores the caller’s
future plan on exit, including on error, rather than
resetting it to "sequential", and no longer registers a
global foreach backend.SEQuential() converting a data.frame
passed as data into a data.table in the
caller’s environment.SEQuential() printing “Creating Survival Curves for
1” (or for each subgroup) with verbose = FALSE when
km.curves = TRUE."_bas" or "_sq" other than at the end
(e.g. bmi_baseline); the indicators are now matched only as
a suffix.multinomial = TRUE), which was fit one-vs-rest but
predicted with a softmax, biasing the weights; it is now fit as
baseline-category logits. This changes weighted multinomial analyses
with three or more treatment values.treat.level is not c(0, 1) or when
multinomial = TRUE. Binary analyses with the default
treat.level are unchanged.log(x) being replaced by
the raw variable in the weight models and some outcome predictions; only
formulas of bare variable names now take the fast model-matrix
path.subgroup is set. This
changes subgroup estimates that use the default outcome model.fixed.cols to factors, so
continuous covariates such as age enter the models as a single term (a
0/1 covariate’s coefficient is now named e.g. sex rather
than sex1). Integer-coded categorical fixed
covariates (e.g. region coded 1-5) must now be supplied as factor or
character columns.SEQopts() that covariates,
cense.numerator, cense.denominator,
visit.numerator and visit.denominator are
single formula strings, and that
numerator/denominator are non-empty. These are
scalar by construction - they are tested downstream with
is.na() and ||, which errors with
'length = 2' in coercion to 'logical(1)' on a vector, or
missing value where TRUE/FALSE needed on a zero-length
value, several frames from the argument that caused it. The error now
names the offending argument at the point it is supplied.
numerator and denominator may still be a
character vector with one formula per treat.level, which is
validated against treat.level as before.weight.spline and
weight.spline.df in SEQopts(). The default
weight models are quadratic in time - followup,
followup_sq, trial and trial_sq
when weight.preexpansion = FALSE, the time column and its
square when weight.preexpansion = TRUE - which only allows
the hazard of treatment to rise or flatten off. With
weight.spline = TRUE each of those quadratics is replaced
by a natural cubic spline basis (splines::ns()) with
weight.spline.df degrees of freedom (default
4, i.e. 3 interior knots at quantiles), so the baseline
hazard can take a flexible shape over follow-up. This covers the
treatment weight models and, where specified, the cense and
visit models, under both settings of
weight.preexpansion. Weight models supplied through
numerator, denominator,
cense.numerator, cense.denominator,
visit.numerator or visit.denominator are left
as written, so ns() terms can also be placed by hand for
finer control.ns(x, df = N) terms in any model formula silently
using a different spline basis when fitting and when predicting.
splines::ns() recomputes its knots from whatever rows it is
passed, and the weight models are fit on one row subset (e.g. the
denominator model excludes followup == 0) and then used to
predict over another, so the knots - and hence the basis - differed
between the two, and differed again in each bootstrap resample. Knots
are now fixed from the full data the model is fit on before fitting, for
the outcome, treatment weight, censoring and visit models alike, so the
basis is identical at fit and prediction time and constant across
resamples. Previously this affected only user-supplied ns()
terms; a spline on followup in a post-expansion weight
model changed weights by up to 0.21 in the package’s own example data.
Formulas that already give explicit
knots/Boundary.knots are unchanged, as are
terms whose variable is absent or non-numeric.end_of_fup, end_of_fup.time,
end_of_fup.type and end_of_fup.window in
SEQopts(). The outcome may be "binary"
(reported as the weighted proportion in each arm) or
"continuous" (the weighted mean). For each trial-period the
measurement at end_of_fup.time is taken, weighted by the
period-trial-specific weight at that time; where no measurement exists
at exactly that time, end_of_fup.window allows a fallback
to the measurement nearest to that time within
[k - window, k + window] (ties broken toward the later
measurement, so that at least k of follow-up has elapsed),
and trial-periods with no measurement anywhere in the window are
censored out of the average. Results are returned in the new
eof.data and eof.comparison slots and via the
new end_of_fup() accessor, with per-arm bootstrap
confidence intervals and the pairwise between-arm difference (in
proportions for a binary outcome, in means for a continuous one) with
its standard error and confidence interval. For binary outcomes the
ratio of proportions is also reported, with a log-scale confidence
interval and a log(Ratio) SE for inverse-variance pooling;
no ratio is given for continuous outcomes, which need not be bounded
away from zero. The estimates table also accounts for how much of each
arm the estimate rests on: Trial-periods (Eligible) is
every trial-period reaching the follow-up time,
Trial-periods (Analysed) those contributing, and
Trial-periods (Censored) those measured at some point but
not within the window, and Trial-periods (No measurement)
those never measured at all, so the three partition the eligible total;
% Censored gives the censored share of that total.
Trial-periods are the unit because one subject can be analysed in one
trial and censored in another. diagnostics() gains
eof.summary (for continuous outcomes: N, mean and SD of the
raw analysed measurements per arm, standing in for the suppressed
outcome count tables) plus eof.unique and
eof.nonunique, accounting for every trial-period at
k across four mutually exclusive categories (measured at
k, measured in the window, excluded outside the window,
excluded with no measurement) against the eligible total; the
trial-period counts partition that total, and the two contributing
categories sum to the trial-periods behind the estimate. Because an
end-of-follow-up outcome is measured at particular times, this is also
the one mode in which the outcome column may contain NA
(recording that no measurement was taken); every other column must still
be complete. See the new “End-of-Follow-up Outcomes” vignette. No
outcome model is fit in this mode, so it is incompatible with
km.curves, hazard, compevent and
the dose-response method, and the expansion is not truncated at the
first outcome event.seed on every bootstrapping example in
the vignettes. Since unseeded runs now draw a genuinely random seed,
these examples produced different confidence intervals on every render;
they are also a better illustration of reproducible practice.numerator
and denominator in SEQopts() now also accept a
character vector with one formula per treat.level (in
treat.level order), fitting a separate
numerator/denominator model - with its own covariates - in each
treatment arm. Only the estimates from the respective arm’s model are
used to construct that arm’s weights. A single string keeps the previous
behaviour (the same formula in every arm). Arm-specific formulas are
only supported for weights estimated on the post-expansion data
(weight.preexpansion = FALSE); the LTFU, visit, and outcome
models are unaffected.risk.times output@info slot as
info$followup.unique and
info$followup.nonunique (per subgroup, mirroring
info$outcome.unique / info$outcome.nonunique).
Both are grouped by baseline treatment over expanded-data rows with an
observed (non-NA) outcome - the person-time the outcome
model is fit on. The non-unique table counts follow-up intervals (so the
non-unique outcome counts divided by these give per-arm event rates);
the unique table counts the distinct subjects contributing follow-up to
each arm. Also shown in the printed diagnostic tables.coxph(formula, data), avoiding the
model.frame/model.matrix rebuild on every
bootstrap iteration: survival::coxph.fit() for the
non-competing-event model and survival::agreg.fit() for the
competing-event Fine-Gray (counting-process) model. The hazard ratio and
CIs are unchanged.finegray() case weights (fgwt), which are
required for a valid subdistribution-hazard estimate and were previously
omitted. This is a no-op for the current hazard simulation (which has
only administrative censoring, so all fgwt are 1) but
corrects the estimate should the simulated data ever carry random
censoring.@info
slot as info$compevent.unique and
info$compevent.nonunique, mirroring the structure of
info$outcome.unique / info$outcome.nonunique.
Both are grouped by baseline treatment; the non-unique table counts all
competing event occurrences in the expanded data and the unique table
counts distinct subjects who experienced the competing event. Both are
NA when no compevent is specified.SEQuential() fit, populate
weight.statistics and outcome.model when
hazard = TRUE.numerator and denominator
weight models are given identical covariates. In that case the
stabilized weights all equal 1 (i.e., no weighting), which is usually a
typo in the denominator argument.SEQuential() helpfile by adding a
per-protocol example.selection.random = TRUE
retains all treated trial-starts, subsamples control trial-starts to the
requested selection.prob fraction, and is reproducible
under a fixed seed; rename the previous smoke test that did not actually
exercise the feature.weight.lower/weight.upper truncation,
weight.p99 truncation,
followup.include/trial.include,
followup.class, weight.lag_condition,
followup.min/followup.max, and
weight.eligible_cols.numerator() and denominator()
returning NULL for every weighted model; they now return
the fitted per-arm numerator/denominator weight models.inline.pred() in the weight
modelsSEQOpts() argument ordering.params@data divergence so expansion uses the
checked and repaired datainternal.hazard()internal.survival() so
each replicate standardizes over the same resample its outcome model was
fit onout), by hoisting row-index computations out of
DT[i] expressions where columns shadow local variablesfastglm.method validation to accept fastglm’s full
range 0-5 (0, column-pivoted QR, is fastglm’s own default and was
previously rejected; 4 is the full-pivoted QR and 5 the Bidiagonal
Divide and Conquer SVD; all six have been supported since fastglm 0.0.1)
and update the documentation accordinglyseed so unseeded runs are genuinely
random. Previously the full .Random.seed vector was stored
and set.seed() silently used only its first element - the
RNG kind code, a constant - so every unseeded run drew identical
bootstrap resamples. The default is now a single random integer drawn
when SEQopts() is called.followup.max is set while survival.max is left
at its Inf default. The check now runs after the
Inf defaults are resolved, which also catches the
previously missed case of a finite survival.max exceeding
the data-derived followup.max.show() erroring on a SEQoutput object
when both subgroup and compevent are specified
(the competing event section passed the model list rather than the
subgroup name to cat()); empty competing event model
entries are now also skipped instead of printing NULL.orig_id * multiplier + copy index) exceeds the 2^53
exact-integer range of doubles for roughly 8+ digit IDs, where
consecutive copy indices round to the same value and distinct copies of
a subject collapse together under by-ID grouping (corrupting
cumulative-product weights). Relabeling now falls back to string
concatenation whenever the arithmetic could overflow, or when IDs are
negative or non-integer."_sq" suffix in the pre-expansion
weight data so a custom indicator.squared no longer fails
with “column not found” in the weight models.method = "dose-response" erroring with a custom
indicator.squared. The expansion created
dose_sq/trial_sq with hardcoded names (and
excluded only the literal dose_sq from expansion variables)
while the default covariates referenced
paste0("dose", indicator.squared), so any non-default
indicator failed in SEQexpand(). All internally generated
squared columns (dose, trial, on both the
expanded data and the survival prediction grid) now follow
indicator.squared, matching the existing convention for
followup, trial and time.trialID construction from the
survival-curve standardization. The per-row paste0() label
was built on the full standardization population (and again on every
bootstrap resample) but never read: predictions there are row-wise with
no by-ID grouping, so bootstrap multiplicity is carried by the
duplicated rows themselves. Results are unchanged.pmax()/pmin() instead of evaluating scalar
max()/min() once per row via
by = .I. Results are unchanged.internal.weights() to
the columns the weight models actually use (ids, structure, treatment
and its baseline copy, formula covariates, censoring/visit/eligibility
indicators, excused flags) instead of copying every column of the
expanded (post-expansion weighting) or input (pre-expansion weighting)
table on every bootstrap iteration. Results are unchanged.SEQexpand() with nomatch = NULL (and remove a
no-op .SDcols there). Original-data rows with no
expansion-grid match - possible under followup.min > 0
or selection.random - were carried as NA-trial rows through
the squared-column computation only to be discarded by the subsequent
inner join with the baseline table. Results are unchanged.seq.int(1:.N) with seq_len(.N) in
the hazard simulation’s per-trial follow-up construction, avoiding a
double allocation per (id, trial) group; the column is now integer,
matching the expansion’s convention. Results are unchanged.glm.package = "parglm" and
bootstrap = TRUE only the main fit uses parglm: the
bootstrap refits always use fastglm, warm-started from the main fit’s
coefficients, which is faster per resample than parglm’s per-fit thread
setup. This was previously a silent switch.SEQestimate() since it is only accurate
to an order of magnitude.risk.comparison
output: RD SE (standard error of the risk difference,
natural scale) and log(RR) SE (standard error of the log
risk ratio). Both are reported whenever bootstrap = TRUE,
regardless of bootstrap.CI_method (the SEs were already
computed internally to form the "se" confidence intervals
but were not retained, and not computed at all under
"percentile").risk.comparison and risk.data, which were
hardcoded as 95% regardless of bootstrap.CI.
They now reflect the requested level (e.g. RD 90% LCI,
90% UCI when bootstrap.CI = 0.9).followup = k correctly represents survival after
k intervals, adding a row at
followup = survival.max + 1 for the final interval’s
estimate.outcome=0 rows from
subsequent periods by truncating each trial at the first event row
(thanks, @francescazaccagnino)expand.only option to SEQopts(). When
TRUE, SEQuential() returns the expanded
data.table directly and skips the analysis steps, for users
who want to inspect or store the expanded dataset on its own.followup.spline = TRUE so the basis is genuinely
non-linear. Splines are now built into the model formula via
splines::ns() instead of being applied as a single-column
transform of followup, and the new
followup.spline.df option (default 4) controls
the number of basis functions. The treatment-by-followup interaction now
uses the same spline basis. Knots are baked from the full expanded
followup once at fit time so the basis is identical at fit
and prediction time across bootstraps and survival grids. Internally,
formula column extraction now uses all.vars(), so
user-supplied covariates may include ns(),
bs(), I(), factor(),
poly() etc. without breaking expansion.format.time() to format_time()
because it wasn’t an S3 method and hence was causing roxygen2 to write
incorrect information in its helpfile.selection.random not being propagated from
SEQopts() to internal parameters.data.table to 2 threads during tests and vignette
builds, and skip the multisession parallel test on CRAN, to comply with
CRAN’s 2-core policy for checks.SEQopts(nthreads = ...) setting to
data.table during SEQuential(). Previously it
was only used by the parglm backend and ignored in the
default serial fastglm path, so data.table ran
at its global default thread count. The previous global setting is
restored when the call finishes.risk.times option to SEQopts(). When
km.curves = TRUE, risk difference and risk ratio (with CIs)
are reported at each requested follow-up time, not just at the end of
follow-up. Requested times are snapped to the latest available follow-up
at or before them, and the final time is always included. The
risk.comparison and risk.data tables gain a
Followup column.factorize() to also coerce categorical (character)
time-varying covariates - and their baseline (_bas)
counterparts - to factors with levels fixed from the full data.
Previously only fixed and treatment columns were factorized, so a
character time-varying covariate could realise different level sets
across bootstrap resamples and raise “newdata provided does not match
fitted model” (most often in bootstrapped hazard analyses on larger
samples or with a smaller bootstrap.sample). Numeric
time-varying covariates are left unchanged.@outcome.modelkm_curve()local() wrappers and made several code
optimizations.internal.weights().SEQopts().SEQuential() time.col validation
detecting and repairing non-zero-indexed time.eligible.col valuestime_varying.cols and
fixed.colsSEQopts()treat.level values exist in the
treatment columnexcused.cols flagsfollowup.min/max
orderingtreat.level length validation for multinomial and
non-multinomial analysescense.eligible and
weight.eligible_colsfollowup.min and
weight.lower from -Inf to 0internal.plot()km_curve() returning list instead of ggplot for
non-subgroup casekm_curve() subtitle conditionrisk.comparison() CIs being NA with
competing eventscbind() with := in expansion chain
to avoid intermediate copymerge() with data.table native join in
expansion data_list combine stepFALSEmatch(TRUE, ...) instead of
which(...)[1] to find first switch/event per groupsapply loop with single matrix multiply in
multinomial predictioncopy() in data_all construction and free data
list in internal_survival.R to reduce peak memory during bootstrapfollowup==0 before adding trialID in
internal.survival to avoid copying entire expanded datasetset.seed() call in
internal.hazard() to make main estimate reproducible. And
also implement fix to ensure the bootstrapping, including both standard
error and percentiles, is deterministic given the seed.hazard_ratio() function now correctly describes the
estimate as “Hazard ratio”covariates() function now returns more nicely
formatted output (with spaces around ~ and +
symbols in the model formulae)table() call with data.table’s
.Ngc() callscopy()These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.