Skip to main content

library.econ

library.econ

Health economics: the costs of a sim, disability-adjusted life years, discounting, and incremental cost-effectiveness ratios.

Used with: agents and compartments; declared and coded modules

Costs are not part of every sim, so these live in the library rather than in core Starsim: ssl.Costs adds a sim’s costs up as results, ssl.DALYs does the same for disability-adjusted life years, ssl.discount() discounts a result over time, and ssl.ICER compares the costs and effects of scenarios, after they have run or as a sim runs.

Classes

Name Description
Costs The costs of a sim, from its results, with their total
DALYs The disability-adjusted life years of a sim: the years lived with disability, plus the years of life lost
ICER Compare the costs and effects of scenarios: incremental cost-effectiveness ratios

Costs

library.econ.Costs(
    unit_costs=None,
    fixed=None,
    start=None,
    deliveries=True,
    **kwargs,
)

The costs of a sim, from its results, with their total

Each delivery made with a cost= (e.g. ss.vaccinate(..., cost=5)) already has a cost result; this adds them up, along with a cost for each event of any other result (e.g. care for each infection) and a fixed cost per unit time. Every cost is a result of this analyzer, named after where it came from, and total is their sum.

Parameters

Name Type Description Default
unit_costs dict the cost of each event of a result, by the result’s path, e.g. {'measles.infection': 50} for $50 of care for each infection, or {'routine.delivered': 5} for $5 a dose of a delivery made without its own cost= None
fixed rate a cost per unit time that does not depend on any result, such as running a program (staff, cold chain, training), e.g. ss.peryear(1000) None
start float / str when the fixed cost starts, read as any time is (see ss.connectors.to_time(): a bare number is a year if the sim has a calendar; default: the start of the sim) None
deliveries bool whether to include the cost result of every module that has one True

Examples

import starsim as ss
import starsim.library as ssl

vx = ss.vaccinate(efficacy=0.9, who=ss.person.age < 5, when=ss.schedule(every=ss.years(1)), coverage=0.5, cost=5)
costs = ssl.Costs(unit_costs={'sir.infection': 50}, fixed=ss.peryear(1000))
sim = ss.Sim(diseases='sir', networks='random', interventions=vx, analyzers=costs)
sim.run()
sim.results.costs.plot()
print(sim.results.costs.total.sum())

Methods

Name Description
fill Work out the costs of some time points
step The costs so far, for what runs during the sim, such as ssl.ICER; the results are final after finalize_results()
fill
library.econ.Costs.fill(ind=slice(None))

Work out the costs of some time points

step
library.econ.Costs.step()

The costs so far, for what runs during the sim, such as ssl.ICER; the results are final after finalize_results()

DALYs

library.econ.DALYs(weights=None, life_lost=None, deaths=None, **kwargs)

The disability-adjusted life years of a sim: the years lived with disability, plus the years of life lost

Years lived with disability (yld) are the time people spend in a state, multiplied by the disability weight of the state. Years of life lost (yll) are the years that each person who dies of a disease would otherwise have lived. Every result is per step, and dalys is their sum.

Parameters

Name Type Description Default
weights dict the disability weight of a result that counts people, by its path, e.g. {'hiv.I': 0.2} None
life_lost float the years of life lost for each death; by default, with agents, those left at each person’s age at death in a standard life table (from the Global Burden of Disease 2019 study). Without agents, ages at death aren’t known, so give this None
deaths list the paths of the results that count deaths, needed only with life_lost (default: each disease’s death) None

Examples

import starsim as ss
import starsim.library as ssl

sir = ss.SIR(p_death=0.01)
sim = ss.Sim(diseases=sir, networks='random', analyzers=ssl.DALYs(weights={'sir.I': 0.1}))
sim.run()
print(sim.results.dalys.dalys.sum())

Methods

Name Description
death_results The paths of the results that count deaths
fill Work out the years lived with disability and, given life_lost, the years of life lost, at some time points
step The years of life lost by those who died in this step, and the results so far, for what runs during the sim, such as ssl.ICER
death_results
library.econ.DALYs.death_results()

The paths of the results that count deaths

fill
library.econ.DALYs.fill(ind=slice(None))

Work out the years lived with disability and, given life_lost, the years of life lost, at some time points

step
library.econ.DALYs.step()

The years of life lost by those who died in this step, and the results so far, for what runs during the sim, such as ssl.ICER

ICER

library.econ.ICER(
    sims=None,
    outcome='dalys.dalys',
    cost='costs.total',
    baseline=None,
    discount=0,
    discount_start=None,
    window=None,
    **kwargs,
)

Compare the costs and effects of scenarios: incremental cost-effectiveness ratios

Each scenario’s cost and outcome are totaled (discounted if discount is given), and the outcome averted is that of the baseline less the scenario’s. The scenarios are ordered by cost, and each is compared with the next cheaper one that isn’t dominated. A scenario is dominated if it costs more and averts no more than a cheaper one, and extendedly dominated if a mix of two others would avert more for the same cost. With several runs of each scenario, their means are compared.

This works in two ways. After the scenarios have run, give them to ssl.ICER(), and read icer.df. Or add it to a sim as an analyzer, after ssl.Costs and ssl.DALYs: the sim then counts as one more scenario, compared at each step with the scenarios given over the same period, so that what runs in the sim can act on the comparison, for example an intervention that follows icer.best(wtp=1000).

Parameters

Name Type Description Default
sims MultiSim / dict / list the sims of each scenario: a run MultiSim, a dict of run sims by label, or a list of run sims None
outcome str the path of the result to avert (default: the total of ssl.DALYs), e.g. ‘measles.infection’ 'dalys.dalys'
cost str the path of the cost result (default: the total of ssl.Costs) 'costs.total'
baseline str the label of the scenario to compare with (default: the first) None
discount float the discount rate per year for both costs and outcomes (see ssl.discount()) 0
discount_start float / str when discounting starts (default: the first time point) None
window dur in a sim, how long a time to compare, ending with the latest step (default: all of it so far); one step long compares the last step alone, e.g. window=ss.years(1) with yearly steps None

Attributes

Name Type Description
df dataframe a row for each scenario, with columns cost, outcome, averted, incremental cost, incremental averted, ICER, dominated, and extended

Examples

# After the runs
msim = ss.parallel({'Nothing': base, 'Vaccine': base.new(interventions=vx)}, n_runs=20)
icer = ssl.ICER(msim, discount=0.03, discount_start=2010)
icer.df
icer.plot()
icer.plot_ceac()
icer.best(wtp=1000)

# During a run, compared with a finished sim
icer = ssl.ICER(dict(Nothing=base.run()), window=ss.years(1))
sim = ss.Sim(..., analyzers=[ssl.Costs(), ssl.DALYs(weights=...), icer])

Methods

Name Description
best The scenario with the highest mean net benefit at a willingness to pay
collect The cost and outcome of each scenario, as arrays of runs by time points
net_benefit The net benefit of each scenario at a willingness to pay per outcome averted: a dataframe with a row for each run and a column for each scenario
plot Plot the cost-effectiveness plane: each scenario’s cost against the outcome it averts, with each run, and the line through those that aren’t dominated
plot_ceac Plot the cost-effectiveness acceptability curve: the fraction of runs in which each scenario is the best, by willingness to pay
step Count this sim as a scenario, as it stands
totals The discounted total cost and outcome of each scenario, as arrays with one value per run, by label
best
library.econ.ICER.best(wtp)

The scenario with the highest mean net benefit at a willingness to pay

Parameters
Name Type Description Default
wtp float the willingness to pay per outcome averted required
collect
library.econ.ICER.collect(sims)

The cost and outcome of each scenario, as arrays of runs by time points

net_benefit
library.econ.ICER.net_benefit(wtp)

The net benefit of each scenario at a willingness to pay per outcome averted: a dataframe with a row for each run and a column for each scenario

plot
library.econ.ICER.plot(**kwargs)

Plot the cost-effectiveness plane: each scenario’s cost against the outcome it averts, with each run, and the line through those that aren’t dominated

Parameters
Name Type Description Default
kwargs dict passed to ss.plot_args()
plot_ceac
library.econ.ICER.plot_ceac(wtp=None, **kwargs)

Plot the cost-effectiveness acceptability curve: the fraction of runs in which each scenario is the best, by willingness to pay

Parameters
Name Type Description Default
wtp array the values of willingness to pay (default: 50 values from 0 up to twice the largest ICER) None
kwargs dict passed to ss.plot_args()
step
library.econ.ICER.step()

Count this sim as a scenario, as it stands

totals
library.econ.ICER.totals()

The discounted total cost and outcome of each scenario, as arrays with one value per run, by label

Functions

Name Description
discount Discount values over time at a yearly rate

discount

library.econ.discount(values, rate, start=None, t=None)

Discount values over time at a yearly rate

Each value at time t (in years) is weighted by (1+rate)**-(t-start), so values before start are not discounted.

Parameters

Name Type Description Default
values Result / array a result (or the results of the runs of a MultiSim), or an array of values at the times t required
rate float the discount rate per year, e.g. 0.03 required
start float / str when discounting starts (default: the first time point) None
t array the time of each value in years (default: the result’s own times) None

Returns

Name Type Description
The discounted values, of the same type as values (so a result can be summed, plotted, etc.)

Examples

cost = ssl.discount(sim.results.costs.total, 0.03, start=2010).sum()