Skip to content

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) -> float

Calculate expected value of sample information.

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.

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.

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.

>>> 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_func EconomicModelFunctionType
  • psa_prior ParameterSet
  • trial_design TrialDesign
  • population float | None (default: None)
  • discount_rate float | None (default: None)
  • time_horizon float | None (default: None)
  • method str (default: 'two_loop')
  • n_outer_loops int (default: 100)
  • n_inner_loops int (default: 1000)
  • metamodel MetamodelName (default: 'linear')
  • seed int | None (default: None)
  • trial_simulator TrialSimulatorType | None (default: None)
  • posterior_sampler PosteriorSamplerType | None (default: None)

Returns: float