voiage.methods.sample_information.evsi
evsi([positional or keyword] model_func: EconomicModelFunctionType = None, [positional or keyword] psa_prior: ParameterSet = None, [positional or keyword] trial_design: TrialDesign = None, [positional or keyword] population: float | None = None, [positional or keyword] discount_rate: float | None = None, [positional or keyword] time_horizon: float | None = None, [positional or keyword] method: str = 'two_loop', [positional or keyword] n_outer_loops: int = 100, [positional or keyword] n_inner_loops: int = 1000, [positional or keyword] metamodel: MetamodelName = 'linear', [keyword-only] seed: int | None = None, [keyword-only] trial_simulator: TrialSimulatorType | None = None, [keyword-only] posterior_sampler: PosteriorSamplerType | None = None) -> floatCalculate expected value of sample information.
Parameters
Section titled “Parameters”model_func : callable
Economic model that maps a :class:~voiage.schema.ParameterSet to a
:class:~voiage.schema.ValueArray.
psa_prior : ParameterSet
Prior PSA sample used as the analysis base.
trial_design : TrialDesign
Proposed study design to evaluate.
population : float, optional
Population size for population scaling.
discount_rate : float, optional
Annual discount rate used for population scaling.
time_horizon : float, optional
Time horizon in years for population scaling.
method : {“two_loop”, “regression”, “efficient”, “moment_based”}
EVSI approximation method.
n_outer_loops : int, default=100
Number of outer Monte Carlo loops for two_loop.
n_inner_loops : int, default=1000
Number of posterior Monte Carlo draws per simulated trial data set for
two_loop. Larger values reduce inner-loop Monte Carlo noise at the
cost of additional model evaluations.
metamodel : str, default=“linear”
Strategy-level surrogate model used by the efficient approximation.
seed : int, optional
A uint64-range seed for reproducible Python two-loop simulation. When
omitted, a fresh local random generator is used.
trial_simulator : callable, optional
Given one joint prior draw, the trial design, and a random generator,
returns data from a declared sampling model. Supply this together with
posterior_sampler for a custom two-loop model. When both callbacks
are omitted, the built-in joint multivariate-normal prior and
known-variance arm-mean likelihood are used.
posterior_sampler : callable, optional
Given the joint prior, simulated data, trial design, requested draw
count, and random generator, returns exactly that many joint posterior
draws as a ParameterSet. It must be supplied together with
trial_simulator.
Returns
Section titled “Returns”float EVSI on a per-decision basis unless population scaling is requested.
EVSI is the increase in expected net benefit from observing a proposed study before making the decision:
.. math::
\mathrm{EVSI} = E_y\left[\max_d E[NB_d \mid y]\right] - \max_d E[NB_d].
Without custom callbacks, the built-in v2 contract estimates a joint
multivariate-normal prior from the PSA draws and uses one mean_<arm>
parameter per trial arm plus a fixed sd_outcome. Current value,
predictive trial outcomes, and posterior value are all integrated under
that fitted Gaussian prior, and correlated parameters are updated jointly.
Custom callbacks may instead declare another coherent sampling and
posterior model. Compatibility estimators remain available for older
workflows but are not stable scientific contracts.
References
Section titled “References”Brennan, A., Kharroubi, S., O’Hagan, A., Chilcott, J., & Claxton, K. (2007). Calculating expected value of sample information via Bayesian numerical analysis. Heath, A., Manolopoulou, I., & Baio, G. (2018). Efficient computation of expected value of sample information using regression-based methods.
Examples
Section titled “Examples”>>> import numpy as np >>> from voiage.methods.sample_information import evsi >>> from voiage.schema import DecisionOption, ParameterSet, TrialDesign, ValueArray >>> def model(psa: ParameterSet) -> ValueArray: … values = np.column_stack([ … 10.0 + psa.parameters[“shift”], … 11.0 - psa.parameters[“shift”], … ]) … return ValueArray.from_numpy(values, [“A”, “B”]) >>> psa = ParameterSet.from_numpy_or_dict({“shift”: np.array([0.1, 0.2, 0.3])}) >>> design = TrialDesign(arms=[DecisionOption(name=“A”, sample_size=10)]) >>> result = evsi(model, psa, design, method=“efficient”) >>> result >= 0.0 True
Parameters:
model_funcEconomicModelFunctionTypepsa_priorParameterSettrial_designTrialDesignpopulationfloat | None(default:None)discount_ratefloat | None(default:None)time_horizonfloat | None(default:None)methodstr(default:'two_loop')n_outer_loopsint(default:100)n_inner_loopsint(default:1000)metamodelMetamodelName(default:'linear')seedint | None(default:None)trial_simulatorTrialSimulatorType | None(default:None)posterior_samplerPosteriorSamplerType | None(default:None)
Returns: float