sensitivity Module#
Monte Carlo sensitivity analysis for compartmental models.
This module provides tools to sample parameter distributions, run thousands of model instances, and aggregate results into percentile envelopes for uncertainty quantification.
Classes#
- class episia.models.sensitivity.SensitivityAnalysis(model_class, param_class, fixed, distributions, n_samples=200, seed=42, n_jobs=1, t_eval_points=500)[source]#
Bases:
objectMonte Carlo sensitivity analysis for compartmental epidemic models.
Example:
from episia.models.sensitivity import SensitivityAnalysis from episia.models import SEIRModel from episia.models.parameters import SEIRParameters sa = SensitivityAnalysis( model_class=SEIRModel, param_class=SEIRParameters, fixed=dict(N=1_000_000, I0=10, E0=50, t_span=(0, 365)), distributions={ 'beta': ('uniform', 0.25, 0.50), 'sigma': ('normal', 1/5.2, 0.02), 'gamma': ('uniform', 1/21, 1/7), }, n_samples=500, seed=42, ) result = sa.run() print(result) result.plot(compartment='I').show() result.plot_metric_distribution('r0').show() result.to_dataframe()
- Parameters:
- __init__(model_class, param_class, fixed, distributions, n_samples=200, seed=42, n_jobs=1, t_eval_points=500)[source]#
- Parameters:
model_class – CompartmentalModel subclass.
param_class – Matching parameters class.
fixed (Dict[str, Any]) – Parameters held constant across all runs.
distributions (Dict[str, Tuple]) – Parameters to sample; values are distribution specs. E.g. {‘beta’: (‘uniform’, 0.2, 0.5)}.
n_samples (int) – Number of Monte Carlo draws.
seed (int | None) – Random seed for reproducibility.
n_jobs (int) – Parallel workers (1 = sequential, -1 = all CPUs).
t_eval_points (int) – Number of time points per trajectory.
- class episia.models.sensitivity.SensitivityResult(t, envelopes, metrics, n_samples, n_failed, param_samples, compartment_names)[source]#
Bases:
objectAggregated result of a Monte Carlo sensitivity analysis.
- Parameters:
- t#
Common time array.
- Type:
- envelopes#
Dict compartment → {‘p5’,’p25’,’p50’,’p75’,’p95’} arrays.
- Type:
Dict[str, Dict[str, numpy.ndarray]]
- metrics#
DataFrame-ready summary of scalar metrics across runs.
- Type:
Dict[str, numpy.ndarray]
- plot(compartment='I', show_samples=False, n_sample_traces=50, backend='plotly', theme='scientific', title=None)[source]#
Plot percentile envelope for a compartment.
- Parameters:
- Returns:
Figure object.
- Return type:
- plot_metric_distribution(metric='r0', backend='plotly', theme='scientific')[source]#
Histogram of a scalar metric across all runs.
Supported Distributions#
('uniform', low, high)('normal', mean, std)('lognormal', mean, sigma)# mean/std of underlying normal('triangular', low, mode, high)('beta_dist', alpha, beta)('fixed', value)# Pin a parameter
Examples#
Basic sensitivity analysis:
from episia.models import SEIRModel
from episia.models.parameters import SEIRParameters
from episia.models.sensitivity import SensitivityAnalysis
sa = SensitivityAnalysis(
model_class=SEIRModel,
param_class=SEIRParameters,
fixed={
'N': 1_000_000,
'I0': 10,
'E0': 50,
't_span': (0, 365)
},
distributions={
'beta': ('uniform', 0.25, 0.50),
'sigma': ('normal', 1/5.2, 0.02),
'gamma': ('uniform', 1/21, 1/7),
},
n_samples=500,
seed=42,
n_jobs=-1 # Use all CPU cores
)
result = sa.run(verbose=True)
print(result) # Summary statistics
result.plot(compartment='I').show() # Trajectory envelope
result.plot_metric_distribution('r0').show() # R₀ distribution
# Export to DataFrame
df = result.to_dataframe()
print(df.describe())
Interpreting results:
# Get summary statistics
summary = result.summary()
print(f"R₀ median: {summary['r0_median']:.2f} [{summary['r0_p5']:.2f}-{summary['r0_p95']:.2f}]")
print(f"Peak infections: {summary['peak_infected_median']:.0f} [{summary['peak_infected_p5']:.0f}-{summary['peak_infected_p95']:.0f}]")
# Access envelope arrays
t = result.t
i_low = result.envelopes['I']['p5']
i_high = result.envelopes['I']['p95']
i_median = result.envelopes['I']['p50']
Comparing compartments:
fig = result.plot(compartment='I', title="Infectious")
fig = result.plot(compartment='R', title="Recovered")
fig = result.plot(compartment='D', title="Deaths")