Computes individual-level state occupation probabilities (SOPs) for each row in a dataset. Optionally aggregates results within strata defined by grouping variables.
Usage
sops(
model,
newdata = NULL,
times,
y_levels = NULL,
absorb = NULL,
by = NULL,
id_var = NULL,
time_var = "time",
p_var = "yprev",
p2_var = NULL,
gap_var = NULL,
time_covariates = NULL,
include_re = FALSE,
n_draws = 100L,
seed = NULL,
posterior_summary = c("mean", "median"),
conf_level = 0.95,
return_draws = FALSE,
...
)Arguments
- model
A fitted model object (e.g.,
vglm,orm, orblrm). Forvglmmodels, the family must be cumulative-logit withreverse = TRUE. Forormmodels, the family must be logistic.- newdata
Optional. A data frame of prediction profiles. When supplied, every row supplies a separate starting state and set of covariates. The internal
rowidcolumn is regenerated. IfNULL, uses the data stored byorm_markov(),blrm_markov(), orvglm_markov()and requires exactly one complete designated starting profile per fitted patient.- times
Required. The consecutive visits at which to calculate SOPs, in increasing order, for example
times = 1:30for daily visits up to day 30. Each value is one transition, so leaving out visits does not skip time; see the section "Choosing visits". Numeric time variables use numeric values; factor-valued visit indices use fitted visit levels.- y_levels
A vector of state levels in fitted outcome order. Its length must agree with the fitted model's threshold count. If
NULL, attempts to infer the levels frommodel.- absorb
The absorbing state.
- by
Optional character vector of variable names to stratify by. When provided, the function aggregates (averages) SOPs within each stratum defined by combinations of these variables. E.g.,
by = "ecog"aggregates within ECOG levels;by = c("ecog", "age_group")aggregates within each combination of ECOG and age group. Rows missing any grouping value are omitted; an error is raised if none remain. This is simple aggregation within observed strata, not G-computation standardization (useavg_sops()for that).- id_var
Character ID column used when
include_re = TRUE. Forblrm,NULLis inferred from wrapper metadata, thenmodel$clusterInfo$namewhen available, otherwise"id". For frequentist models,id_varis used for stored starting-profile validation and refit bootstrap metadata, not for ordinary user-supplied prediction rows.- time_var
Name of the time variable in the model.
- p_var
Name of the previous state variable in the model.
- p2_var
Optional second previous-state variable.
NULLuses a first-order Markov recursion; a non-NULLcolumn name uses a second-order recursion.- gap_var
Optional name of the variable holding the time elapsed since the previous visit, if the model includes one. Each transition then uses the difference between consecutive values of
times(the first value for the first transition), unlesstime_covariatescontains this column, sotimesmay skip visits. See the section "Choosing visits".- time_covariates
Optional time-varying covariate lookup table for explicit basis columns. Registered inline terms such as
rms::rcs(time, 4)andrms::lsp(time, c(3, 7))can be used without supplyingtime_covariates.- include_re
Logical. For
rmsb::blrm()fits withcluster(), include fitted random-effect draws in posterior predictions for known IDs.- n_draws
Integer number of posterior draws to sample for
blrm, orNULLto use all stored draws. Defaults to 100.- seed
Optional random seed for reproducible random draw sampling.
- posterior_summary
Summary used for
blrmposterior SOP draws:"mean"or"median".- conf_level
Confidence level for
blrmposterior intervals.- return_draws
Logical. For
blrm, store posterior SOP draws for extraction withget_draws(). Large draw objects are guarded to protect memory.- ...
Additional arguments (currently unused).
Value
A data frame of class markov_sops containing:
- rowid
Row identifier from newdata (omitted if
byis specified)- time
Time point
- state
State name
- estimate
Probability of being in the state (individual-level or stratum average)
- conf.low, conf.high, std.error
For
blrmfits, posterior uncertainty summaries computed directly from SOP draws- (by variables)
Stratification variables if
byis specified
Plus all columns from newdata (for individual-level results).
Details
For supported frequentist models, pass the result to
inferences(method = "delta", vcov = "conditional") for analytical
confidence intervals. These account for coefficient estimation while
treating the starting states and covariates used for prediction as given.
sops() does not support unconditional analytical variance. See inferences()
for model restrictions and other inference methods.
This function wraps soprob_markov() and converts its array output to a tidy
data frame. The output contains one row per patient-time-state combination
(or stratum-time-state if by is used).
Automatic prediction from a wrapper-fitted model uses the cohort-wide
designated first_followup_time retained before response-driven model-frame
omission. The transition response is not required on that row, but ID,
modeled predictors, time information, and previous state must be complete.
Each included patient must contribute at least one usable fitted transition
somewhere; later rows are not substituted for a missing starting profile.
For rmsb::blrm() models, SOPs are computed on sampled posterior draws and
then summarized. The point estimate is the requested posterior summary of the
SOP draws, not a plug-in calculation from summarized model parameters.
State-wise medians and interval bounds are not constrained to sum to one
across states; use posterior_summary = "mean" when the displayed estimates
themselves need to preserve total probability. Draw-level probabilities
stored with return_draws = TRUE remain normalized within each draw.
Model Requirements:
For vglm models, only the cumulative-logit family with reverse = TRUE is
supported. For orm models, only the logistic family is supported. This is
because the package's Markov simulation logic expects
higher-numbered states to represent worse outcomes, and uses reverse cumulative
probabilities to model the probability of being in state k or worse.
Stratification:
When by is specified, the function:
Computes individual-level SOPs for all patients
Groups results by time, state, and the specified variables
Averages the SOPs within each group
This aggregation preserves heterogeneity across observed strata without
creating counterfactual scenarios (unlike G-computation in avg_sops()).
For computing marginal/standardized SOPs (G-computation), use avg_sops()
instead, which creates counterfactual datasets and averages over individuals.
Choosing visits
SOPs are calculated one visit at a time. The first value of times is the
first transition from the starting state, and each later value is one more
transition. The values set the time variable, and any time-varying
covariates, for each transition; they do not say how much time passes
between transitions. Leaving out visits therefore does not skip time. With
daily visits, times = c(1, 7, 14) gives the probabilities after 1, 2, and 3
transitions, labelled 1, 7, and 14, instead of the probabilities on days 7
and 14. To get SOPs at selected visits, request every visit, such as
times = 1:14, and keep the rows you need.
When newdata is omitted, each patient starts from their state before the
first follow-up visit (first_followup_time of the fitting wrapper), so
times must begin at that visit. Each row of a supplied newdata starts
from its previous state at the first requested visit, which may be a later
visit.
A warning is given when times leaves out visits that occur in the data the
model was fitted to, is not in increasing order, or, when newdata is
omitted, does not begin at the first follow-up visit. Times after the last
fitted visit are allowed. There is no warning when gap_var is supplied,
because each transition then uses its own elapsed time, so the visits may be
spaced unevenly.
See also
avg_sops() for marginal SOPs, soprob_markov() for the underlying
computation.
Examples
if (FALSE) { # \dontrun{
# Individual-level SOPs
sops_ind <- sops(fit, newdata = baseline_data, times = 1:30, y_levels = 1:6)
# Stratified by ECOG performance status
sops_ecog <- sops(fit, newdata = baseline_data, times = 1:30, y_levels = 1:6,
by = "ecog")
# Stratified by multiple variables
sops_strat <- sops(fit, newdata = baseline_data, times = 1:30, y_levels = 1:6,
by = c("ecog", "age_group"))
# Compatible with inferences()
sops_strat |> inferences(method = "mvn", n_draws = 1000)
} # }
