| Title: | Distributional Cost-Effectiveness Analysis for Health Technology Assessment |
|---|---|
| Description: | Implements distributional cost-effectiveness analysis (DCEA) as described in Cookson et al. (2020, ISBN:9780198838197) and the methods endorsed by NICE (2025) for health technology evaluation. Provides functions for both aggregate and full-form DCEA, inequality measurement (Atkinson index, Gini coefficient, slope index of inequality, relative index of inequality), social welfare function evaluation, equity-efficiency impact plane visualisation, and sensitivity analysis over inequality aversion parameters. Includes baseline health distributions for England (by IMD quintile), Canada (income quintile), and global WHO regions. Suitable for academic research, health technology assessment submissions, and public health policy analysis. |
| Authors: | Shubhram Pandey [aut, cre] (ORCID: <https://orcid.org/0009-0005-2303-1592>) |
| Maintainer: | Shubhram Pandey <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.1.0 |
| Built: | 2026-05-24 06:22:26 UTC |
| Source: | https://github.com/heorlytics/dceasimr |
Implements distributional cost-effectiveness analysis (DCEA) as described in Cookson et al. (2020) and methods endorsed by NICE (2025). Provides functions for aggregate and full-form DCEA, inequality measurement, social welfare function evaluation, equity-efficiency impact plane visualisation, and sensitivity analysis.
run_aggregate_dcea — Aggregate DCEA (Love-Koh 2019)
run_full_dcea — Full-form DCEA with subgroup data
calc_ede — Equally Distributed Equivalent health
plot_equity_impact_plane — Equity-efficiency impact plane
get_baseline_health — Preloaded baseline distributions
#'
Cookson R, Griffin S, Norheim OF, Culyer AJ (2020). Distributional Cost-Effectiveness Analysis. Oxford University Press. Oxford University Press (ISBN:9780198838197).
Love-Koh J, Asaria M, Cookson R, Griffin S (2019). The Social Distribution of Health: Estimating Quality-Adjusted Life Expectancy in England. Value in Health 22(5): 518-526. doi:10.1016/j.jval.2018.10.007
Asaria M, Griffin S, Cookson R (2016). Distributional Cost-Effectiveness Analysis: A Tutorial. Medical Decision Making 36(1): 8-19. doi:10.1177/0272989X15583266
Maintainer: Shubhram Pandey [email protected] (ORCID)
Useful links:
Constructs the five-step inequality staircase data frame from individual component vectors. The staircase traces how the distribution of health gains is shaped at each stage: prevalence, eligibility, uptake, clinical effect, and net opportunity cost.
build_staircase_data( group, group_labels, prevalence, eligibility, uptake, clinical_effect, opportunity_cost )build_staircase_data( group, group_labels, prevalence, eligibility, uptake, clinical_effect, opportunity_cost )
group |
Integer vector of group identifiers (1 = most deprived). |
group_labels |
Character vector of group labels. |
prevalence |
Numeric vector: disease prevalence by group (proportion). |
eligibility |
Numeric vector: proportion eligible for the intervention by group. |
uptake |
Numeric vector: uptake rate by group (0-1). |
clinical_effect |
Numeric vector: incremental QALY gain by group. |
opportunity_cost |
Numeric vector: QALYs displaced per group via budget impact. |
A tibble in long format suitable for
plot_inequality_staircase.
build_staircase_data( group = 1:5, group_labels = paste("IMD Q", 1:5), prevalence = c(0.08, 0.07, 0.06, 0.05, 0.04), eligibility = c(0.70, 0.72, 0.74, 0.76, 0.78), uptake = c(0.60, 0.64, 0.68, 0.72, 0.76), clinical_effect = c(0.30, 0.38, 0.45, 0.52, 0.58), opportunity_cost = c(0.05, 0.05, 0.05, 0.05, 0.05) )build_staircase_data( group = 1:5, group_labels = paste("IMD Q", 1:5), prevalence = c(0.08, 0.07, 0.06, 0.05, 0.04), eligibility = c(0.70, 0.72, 0.74, 0.76, 0.78), uptake = c(0.60, 0.64, 0.68, 0.72, 0.76), clinical_effect = c(0.30, 0.38, 0.45, 0.52, 0.58), opportunity_cost = c(0.05, 0.05, 0.05, 0.05, 0.05) )
Convenience wrapper that computes SII, RII, concentration index, Atkinson
index (for multiple values), and Gini coefficient and
returns them as a tidy data frame.
calc_all_inequality_indices( data, health_var, group_var, weight_var, epsilon_values = c(0.5, 1, 2) )calc_all_inequality_indices( data, health_var, group_var, weight_var, epsilon_values = c(0.5, 1, 2) )
data |
A data frame with health and group columns. |
health_var |
Name of the health variable column (character). |
group_var |
Name of the socioeconomic group column (ordered integer, 1 = most deprived). |
weight_var |
Name of the population share column (sums to 1). |
epsilon_values |
Numeric vector of |
A tibble with columns index, value, and
description.
df <- tibble::tibble( group = 1:5, mean_hale = c(60, 63, 66, 69, 72), pop_share = rep(0.2, 5) ) calc_all_inequality_indices(df, "mean_hale", "group", "pop_share")df <- tibble::tibble( group = 1:5, mean_hale = c(60, 63, 66, 69, 72), pop_share = rep(0.2, 5) ) calc_all_inequality_indices(df, "mean_hale", "group", "pop_share")
The Atkinson index measures the extent of inequality in the health
distribution, explicitly incorporating a parameter
representing inequality aversion. Higher values give
more weight to health differences at the bottom of the distribution.
calc_atkinson_index(health_dist, pop_weights, epsilon = 1)calc_atkinson_index(health_dist, pop_weights, epsilon = 1)
health_dist |
Numeric vector of health values across population groups. |
pop_weights |
Numeric vector of population weights (need not sum to 1; will be normalised internally). |
epsilon |
Inequality aversion parameter (default = 1). Must be
non-negative. When |
Atkinson index value in [0, 1]. A value of 0 indicates perfect equality; a value approaching 1 indicates maximum inequality.
Atkinson AB (1970). On the Measurement of Inequality. Journal of Economic Theory 2(3): 244-263. doi:10.1016/0022-0531(70)90039-6
# Perfect equality calc_atkinson_index(rep(70, 5), rep(0.2, 5), epsilon = 1) # Gradient across groups calc_atkinson_index(c(60, 63, 66, 69, 72), rep(0.2, 5), epsilon = 1)# Perfect equality calc_atkinson_index(rep(70, 5), rep(0.2, 5), epsilon = 1) # Gradient across groups calc_atkinson_index(c(60, 63, 66, 69, 72), rep(0.2, 5), epsilon = 1)
Measures the degree to which a health variable is concentrated among socioeconomically advantaged or disadvantaged groups. A negative value indicates the health variable (e.g., illness) is concentrated among the deprived; a positive value indicates concentration among the advantaged.
calc_concentration_index( data, health_var, group_var, weight_var, rank_var = NULL, type = c("standard", "erreygers", "wagstaff") )calc_concentration_index( data, health_var, group_var, weight_var, rank_var = NULL, type = c("standard", "erreygers", "wagstaff") )
data |
A data frame with health and group columns. |
health_var |
Name of the health variable column (character). |
group_var |
Name of the socioeconomic group column (ordered integer, 1 = most deprived). |
weight_var |
Name of the population share column (sums to 1). |
rank_var |
Name of the socioeconomic rank variable (ridit scores,
0 = lowest, 1 = highest). If |
type |
Concentration index variant: |
A named list with ci (concentration index), se,
and type.
Erreygers G (2009). Correcting the Concentration Index. Journal of Health Economics 28(2): 504-515. doi:10.1016/j.jhealeco.2008.02.003
df <- tibble::tibble( group = 1:5, mean_hale = c(60, 63, 66, 69, 72), pop_share = rep(0.2, 5) ) calc_concentration_index(df, "mean_hale", "group", "pop_share")df <- tibble::tibble( group = 1:5, mean_hale = c(60, 63, 66, 69, 72), pop_share = rep(0.2, 5) ) calc_concentration_index(df, "mean_hale", "group", "pop_share")
Uses the Atkinson social welfare function to calculate EDE health — the
level of health that, if equally distributed, would generate the same
social welfare as the actual distribution given inequality aversion
parameter .
calc_ede(health_dist, pop_weights, eta = 1)calc_ede(health_dist, pop_weights, eta = 1)
health_dist |
Numeric vector of health values by group (must be strictly positive). |
pop_weights |
Numeric vector of population weights (will be normalised to sum to 1). |
eta |
Inequality aversion parameter (numeric scalar, default = 1).
|
EDE health value (numeric scalar). Returns NA with a
warning if any health values are non-positive.
Atkinson AB (1970). On the Measurement of Inequality. Journal of Economic Theory 2(3): 244-263. doi:10.1016/0022-0531(70)90039-6
health <- c(60, 63, 66, 69, 72) weights <- rep(0.2, 5) # eta = 0: arithmetic mean calc_ede(health, weights, eta = 0) # eta = 1: geometric mean calc_ede(health, weights, eta = 1) # eta = 5: high inequality aversion calc_ede(health, weights, eta = 5)health <- c(60, 63, 66, 69, 72) weights <- rep(0.2, 5) # eta = 0: arithmetic mean calc_ede(health, weights, eta = 0) # eta = 1: geometric mean calc_ede(health, weights, eta = 1) # eta = 5: high inequality aversion calc_ede(health, weights, eta = 5)
Evaluates calc_ede across a vector of values and
returns a tidy tibble. This is the basis for EDE profile plots as
described in the York DCEA handbook.
calc_ede_profile(health_dist, pop_weights, eta_range = seq(0, 10, 0.1))calc_ede_profile(health_dist, pop_weights, eta_range = seq(0, 10, 0.1))
health_dist |
Numeric vector of health values by group. |
pop_weights |
Numeric vector of population weights. |
eta_range |
Numeric vector of |
A tibble with columns eta and ede.
health <- c(60, 63, 66, 69, 72) weights <- rep(0.2, 5) calc_ede_profile(health, weights)health <- c(60, 63, 66, 69, 72) weights <- rep(0.2, 5) calc_ede_profile(health, weights)
Convenience function that returns equity weights for each group across
a range of values. Useful for understanding how the choice of
inequality aversion changes the implied weights.
calc_equity_weight_profile( baseline_health, pop_weights, eta_range, group_labels = NULL )calc_equity_weight_profile( baseline_health, pop_weights, eta_range, group_labels = NULL )
baseline_health |
Numeric vector of baseline health by group. |
pop_weights |
Numeric vector of population weights. |
eta_range |
Numeric vector of |
group_labels |
Optional character vector of group labels. |
A tidy tibble with columns eta, group,
group_label (if provided), and equity_weight.
baseline <- c(60, 63, 66, 69, 72) weights <- rep(0.2, 5) calc_equity_weight_profile(baseline, weights, eta_range = 0:5)baseline <- c(60, 63, 66, 69, 72) weights <- rep(0.2, 5) calc_equity_weight_profile(baseline, weights, eta_range = 0:5)
Applies equity weights to per-group NHB values to obtain the population-level equity-weighted NHB. This is the key summary statistic from the social welfare perspective.
calc_equity_weighted_nhb(nhb_by_group, equity_weights, pop_weights)calc_equity_weighted_nhb(nhb_by_group, equity_weights, pop_weights)
nhb_by_group |
Numeric vector of net health benefit per group. |
equity_weights |
Numeric vector of equity weights from
|
pop_weights |
Numeric vector of population weights. |
Scalar equity-weighted NHB (numeric).
baseline <- c(60, 63, 66, 69, 72) weights <- rep(0.2, 5) ew <- calc_equity_weights(baseline, weights, eta = 1) nhb <- c(100, 150, 200, 250, 300) calc_equity_weighted_nhb(nhb, ew, weights)baseline <- c(60, 63, 66, 69, 72) weights <- rep(0.2, 5) ew <- calc_equity_weights(baseline, weights, eta = 1) nhb <- c(100, 150, 200, 250, 300) calc_equity_weighted_nhb(nhb, ew, weights)
Derives equity weights from the Atkinson social welfare function. Equity
weights represent the relative social value of a one-unit health gain in
each socioeconomic group given inequality aversion .
calc_equity_weights(baseline_health, pop_weights, eta = 1, normalise = TRUE)calc_equity_weights(baseline_health, pop_weights, eta = 1, normalise = TRUE)
baseline_health |
Numeric vector of baseline health (HALE) by group (ordered from most to least deprived). |
pop_weights |
Numeric vector of population weights. |
eta |
Inequality aversion parameter (default = 1). |
normalise |
Logical. If |
For the Atkinson SWF, the equity weight for group is proportional
to : groups with lower baseline health receive higher
weights when .
Named numeric vector of equity weights, one per group.
Cookson R, Griffin S, Norheim OF, Culyer AJ (2020). Distributional Cost-Effectiveness Analysis. Oxford University Press. Oxford University Press (ISBN:9780198838197).
Robson M, Asaria M, Cookson R, Tsuchiya A, Ali S (2017). Eliciting the Level of Health Inequality Aversion in England. Health Economics 26(10): 1328-1334. doi:10.1002/hec.3386
baseline <- c(60, 63, 66, 69, 72) weights <- rep(0.2, 5) calc_equity_weights(baseline, weights, eta = 1)baseline <- c(60, 63, 66, 69, 72) weights <- rep(0.2, 5) calc_equity_weights(baseline, weights, eta = 1)
Computes the Gini coefficient as a measure of health inequality across socioeconomic groups. The Gini ranges from 0 (perfect equality) to 1 (maximum inequality).
calc_gini(health_dist, pop_weights = NULL)calc_gini(health_dist, pop_weights = NULL)
health_dist |
Numeric vector of health values (ordered from lowest to highest group). |
pop_weights |
Optional numeric vector of population weights. If
|
Gini coefficient (numeric scalar in [0, 1]).
calc_gini(c(60, 63, 66, 69, 72), pop_weights = rep(0.2, 5))calc_gini(c(60, 63, 66, 69, 72), pop_weights = rep(0.2, 5))
The RII is the SII expressed relative to the mean health level. An RII of 0.20 means the most deprived group has health 20 across the full socioeconomic range.
calc_rii(data, health_var, group_var, weight_var)calc_rii(data, health_var, group_var, weight_var)
data |
A data frame with health and group columns. |
health_var |
Name of the health variable column (character). |
group_var |
Name of the socioeconomic group column (ordered integer, 1 = most deprived). |
weight_var |
Name of the population share column (sums to 1). |
A named list with elements rii, sii, se_rii,
p_value, and model.
df <- tibble::tibble( group = 1:5, mean_hale = c(60, 63, 66, 69, 72), pop_share = rep(0.2, 5) ) calc_rii(df, "mean_hale", "group", "pop_share")df <- tibble::tibble( group = 1:5, mean_hale = c(60, 63, 66, 69, 72), pop_share = rep(0.2, 5) ) calc_rii(df, "mean_hale", "group", "pop_share")
Fits a weighted regression of health on ridit scores to estimate the absolute health difference between the most and least deprived groups. The SII is the regression coefficient on the ridit score, interpretable as the total health gap across the full socioeconomic range.
calc_sii(data, health_var, group_var, weight_var)calc_sii(data, health_var, group_var, weight_var)
data |
A data frame with health and group columns. |
health_var |
Name of the health variable column (character). |
group_var |
Name of the socioeconomic group column (ordered integer, 1 = most deprived). |
weight_var |
Name of the population share column (sums to 1). |
A named list with elements:
Slope Index of Inequality (numeric)
Relative Index of Inequality (numeric)
Standard error of SII
p-value for SII
The underlying lm object
Mackenbach JP, Kunst AE (1997) Measuring the magnitude of socioeconomic inequalities in health: an overview of available measures illustrated with two examples from Europe. Social Science and Medicine 44(6): 757-771. doi:10.1016/S0277-9536(96)00073-1
df <- tibble::tibble( group = 1:5, mean_hale = c(60, 63, 66, 69, 72), pop_share = rep(0.2, 5) ) calc_sii(df, "mean_hale", "group", "pop_share")df <- tibble::tibble( group = 1:5, mean_hale = c(60, 63, 66, 69, 72), pop_share = rep(0.2, 5) ) calc_sii(df, "mean_hale", "group", "pop_share")
Wraps calc_ede to compute social welfare before and after an
intervention and decomposes the welfare change into efficiency and equity
components.
calc_social_welfare(baseline_health, post_health, pop_weights, eta = 1)calc_social_welfare(baseline_health, post_health, pop_weights, eta = 1)
baseline_health |
Numeric vector of pre-intervention health by group. |
post_health |
Numeric vector of post-intervention health by group. |
pop_weights |
Numeric vector of population weights. |
eta |
Inequality aversion parameter (default = 1). |
A named list with elements:
ede_baselineEDE health before intervention.
ede_postEDE health after intervention.
delta_edeChange in EDE (welfare gain).
efficiency_componentChange in mean health.
equity_componentChange in EDE minus change in mean.
pre <- c(60, 63, 66, 69, 72) post <- c(61, 64, 66.5, 69.2, 72.1) w <- rep(0.2, 5) calc_social_welfare(pre, post, w, eta = 1)pre <- c(60, 63, 66, 69, 72) post <- c(61, 64, 66.5, 69.2, 72.1) w <- rep(0.2, 5) calc_social_welfare(pre, post, w, eta = 1)
Health-Adjusted Life Expectancy for Canada, stratified by household income quintile. For use in Canadian DCEA analyses (CADTH workflow).
canada_income_halecanada_income_hale
A tibble with 5 rows and 9 variables analogous to
england_imd_hale but with income-based stratification.
Statistics Canada, Health-Adjusted Life Expectancy by income quintile.
The Generalised Lorenz Curve (GLC) scales the Lorenz curve by mean health, making it sensitive to both inequality and average health level.
compute_generalised_lorenz_data( health_dist, pop_weights, label = "Distribution" )compute_generalised_lorenz_data( health_dist, pop_weights, label = "Distribution" )
health_dist |
Numeric vector of health values by group. |
pop_weights |
Numeric vector of population weights. |
label |
Optional character label for this curve. |
A tibble with columns cum_pop, cum_health_generalised,
and label.
compute_generalised_lorenz_data(c(60, 63, 66, 69, 72), rep(0.2, 5))compute_generalised_lorenz_data(c(60, 63, 66, 69, 72), rep(0.2, 5))
Returns the coordinates of the Lorenz curve for a health distribution. Groups are ordered from lowest to highest health (most to least deprived).
compute_lorenz_data(health_dist, pop_weights, label = "Distribution")compute_lorenz_data(health_dist, pop_weights, label = "Distribution")
health_dist |
Numeric vector of health values by group. |
pop_weights |
Numeric vector of population weights. |
label |
Optional character label for this curve. |
A tibble with columns cum_pop (cumulative population share),
cum_health (cumulative health share), and label.
compute_lorenz_data(c(60, 63, 66, 69, 72), rep(0.2, 5))compute_lorenz_data(c(60, 63, 66, 69, 72), rep(0.2, 5))
Ridit scores are used as the socioeconomic rank variable in concentration
index calculations. For group , the ridit is the cumulative
population share up to the midpoint of group .
compute_ridit_scores(pop_shares)compute_ridit_scores(pop_shares)
pop_shares |
Numeric vector of population proportions (ordered from most to least deprived, sums to 1). |
Numeric vector of ridit scores in [0, 1].
compute_ridit_scores(rep(0.2, 5))compute_ridit_scores(rep(0.2, 5))
Baseline HALE (Health-Adjusted Life Expectancy) at birth for England, stratified by Index of Multiple Deprivation (IMD) quintile. Quintile 1 is the most deprived; quintile 5 is the least deprived.
england_imd_haleengland_imd_hale
A tibble with 5 rows and 14 variables:
Integer (1-5). 1 = most deprived.
Integer (1-5). Standard group identifier (same as imd_quintile).
Character. Human-readable quintile label.
Character. Standard group label (same as quintile_label).
Numeric. HALE at birth (years), both sexes (standard name).
Numeric. HALE at birth (years), both sexes.
Numeric. HALE at birth (years), males.
Numeric. HALE at birth (years), females.
Numeric. Standard error of mean_hale (standard name).
Numeric. Standard error of mean_hale_all.
Numeric. Proportion of population in quintile (sums to 1).
Numeric. Ridit score for concentration index.
Integer. Reference data year.
Character. Data source.
Office for Health Inequalities and Disparities (OHID) / Public Health England Health Profiles Plus. Proxy values based on published PHE data and interpolation from peer-reviewed literature.
Love-Koh J et al. (2019). Value in Health 22(5): 518-526. doi:10.1016/j.jval.2018.10.007
Age- and IMD-stratified EQ-5D-3L utility norms for England. Useful for assigning baseline quality of life weights in full-form DCEA.
england_imd_qolengland_imd_qol
A tibble with 40 rows (5 IMD quintiles x 8 age bands) and 6 variables:
Integer (1-5).
Character. Age band label.
Numeric. Mean EQ-5D-3L utility score.
Numeric. Standard error.
Numeric. Quality-Adjusted Life Expectancy remaining (years).
Character. Data source citation.
Adapted from Ara R & Brazier JE (2010) with IMD gradient adjustments from Petrou et al. (Population Health Metrics).
A hypothetical cost-effectiveness analysis output for a lung cancer (NSCLC) treatment versus standard of care. Used in package examples and vignettes to demonstrate DCEA functions without requiring real data.
example_cea_outputexample_cea_output
A list with two elements:
A tibble with columns: strategy,
total_qaly, total_cost, inc_qaly,
inc_cost, icer, nhb_at_20k, nhb_at_30k.
A data frame of 1000 PSA iterations with columns
inc_qaly and inc_cost.
Hypothetical data generated for illustration purposes only.
Writes a multi-sheet Excel workbook with NICE-formatted DCEA output, including the summary table, per-group results, inequality indices, and social welfare profile.
export_dcea_excel(dcea_result, filepath, include_plots = FALSE)export_dcea_excel(dcea_result, filepath, include_plots = FALSE)
dcea_result |
Object of class |
filepath |
Output |
include_plots |
Logical. Embed plots as images in the Excel workbook
(default: |
Invisibly returns filepath.
result <- run_aggregate_dcea( icer = 25000, inc_qaly = 0.5, inc_cost = 12500, population_size = 10000, wtp = 20000 ) export_dcea_excel(result, file.path(tempdir(), "my_dcea_results.xlsx"))result <- run_aggregate_dcea( icer = 25000, inc_qaly = 0.5, inc_cost = 12500, population_size = 10000, wtp = 20000 ) export_dcea_excel(result, file.path(tempdir(), "my_dcea_results.xlsx"))
Renders a complete DCEA report as an HTML, Word, or PDF document using R Markdown.
generate_dcea_report( dcea_result, format = "html", filepath = NULL, template = "nice_submission" )generate_dcea_report( dcea_result, format = "html", filepath = NULL, template = "nice_submission" )
dcea_result |
Object of class |
format |
Output format: |
filepath |
Output file path. If |
template |
Report template: |
Invisibly returns the output file path.
result <- run_aggregate_dcea( icer = 25000, inc_qaly = 0.5, inc_cost = 12500, population_size = 10000, wtp = 20000 ) generate_dcea_report(result, format = "html")result <- run_aggregate_dcea( icer = 25000, inc_qaly = 0.5, inc_cost = 12500, population_size = 10000, wtp = 20000 ) generate_dcea_report(result, format = "html")
Creates a summary table formatted according to NICE (2025) Methods Support Document guidance for DCEA as supplementary evidence in technology appraisals.
generate_nice_table(dcea_result, format = "tibble", include_psa = FALSE)generate_nice_table(dcea_result, format = "tibble", include_psa = FALSE)
dcea_result |
Object of class |
format |
Output format: |
include_psa |
Logical. Include probabilistic uncertainty columns if
PSA data are available (default: |
A formatted table object of the requested type.
result <- run_aggregate_dcea( icer = 25000, inc_qaly = 0.5, inc_cost = 12500, population_size = 10000, wtp = 20000 ) generate_nice_table(result, format = "tibble")result <- run_aggregate_dcea( icer = 25000, inc_qaly = 0.5, inc_cost = 12500, population_size = 10000, wtp = 20000 ) generate_nice_table(result, format = "tibble")
Returns pre-loaded HALE (Health-Adjusted Life Expectancy) data stratified by equity subgroup for use in DCEA. Data are sourced from ONS/OHID (England), Statistics Canada, and the WHO Global Health Observatory.
get_baseline_health( country = "england", equity_var = "imd_quintile", age_group = "all", sex = "all", year = NULL )get_baseline_health( country = "england", equity_var = "imd_quintile", age_group = "all", sex = "all", year = NULL )
country |
Character. One of |
equity_var |
Character. Stratification variable. Options depend on
|
age_group |
Character. Age filter (default |
sex |
Character. Sex filter: |
year |
Integer. Data year. Uses most recent available if |
A tibble with columns: group, group_label,
mean_hale, se_hale, pop_share,
cumulative_rank, source, year.
england_baseline <- get_baseline_health("england", "imd_quintile") england_baselineengland_baseline <- get_baseline_health("england", "imd_quintile") england_baseline
Joins a CEA result data frame (one row per equity subgroup) with a
baseline health distribution returned by get_baseline_health.
This is the key data-preparation step before running DCEA.
merge_cea_with_baseline(cea_output, baseline, by = "group")merge_cea_with_baseline(cea_output, baseline, by = "group")
cea_output |
Data frame of CEA results with at least one column
matching the baseline |
baseline |
Tibble returned by |
by |
Column name to join on (default: |
A merged tibble suitable for run_full_dcea.
baseline <- get_baseline_health("england", "imd_quintile") cea_out <- tibble::tibble( group = 1:5, inc_qaly = c(0.3, 0.4, 0.5, 0.55, 0.6), inc_cost = rep(10000, 5) ) merge_cea_with_baseline(cea_out, baseline, by = "group")baseline <- get_baseline_health("england", "imd_quintile") cea_out <- tibble::tibble( group = 1:5, inc_qaly = c(0.3, 0.4, 0.5, 0.55, 0.6), inc_cost = rep(10000, 5) ) merge_cea_with_baseline(cea_out, baseline, by = "group")
Normalise population weights to sum to 1
normalise_weights(weights)normalise_weights(weights)
weights |
Numeric vector of weights. |
Normalised numeric vector.
normalise_weights(c(1, 2, 3, 4, 5))normalise_weights(c(1, 2, 3, 4, 5))
A full DCEA worked example based on published literature for a non-small-cell lung cancer treatment. Includes subgroup-level CEA results by IMD quintile for use in full-form DCEA demonstrations.
nsclc_dcea_examplensclc_dcea_example
A list with elements:
Tibble of per-IMD-quintile CEA results.
Baseline health distribution for NSCLC population.
Staircase data for the inequality staircase plot.
Adapted from published NSCLC DCEA literature for illustration.
Creates a tornado diagram showing the influence of each parameter on the net health benefit. Parameters are sorted by range (most influential at the top).
plot_dcea_tornado(sensitivity_result)plot_dcea_tornado(sensitivity_result)
sensitivity_result |
Output from |
A ggplot2 tornado diagram.
result <- run_aggregate_dcea( icer = 25000, inc_qaly = 0.5, inc_cost = 12500, population_size = 10000, wtp = 20000 ) sa <- run_dcea_sensitivity(result) plot_dcea_tornado(sa)result <- run_aggregate_dcea( icer = 25000, inc_qaly = 0.5, inc_cost = 12500, population_size = 10000, wtp = 20000 ) sa <- run_dcea_sensitivity(result) plot_dcea_tornado(sa)
Shows how equity-weighted NHB (or EDE health) changes as inequality
aversion () increases. The profile reveals the critical
at which an intervention becomes welfare-improving after accounting for
equity concerns.
plot_ede_profile( dcea_result, eta_range = seq(0, 15, 0.1), comparators = NULL, show_benchmark_eta = TRUE )plot_ede_profile( dcea_result, eta_range = seq(0, 15, 0.1), comparators = NULL, show_benchmark_eta = TRUE )
dcea_result |
DCEA result object. |
eta_range |
Numeric vector of |
comparators |
Optional list of additional DCEA result objects to overlay on the same plot. |
show_benchmark_eta |
Logical. Mark commonly used |
A ggplot2 object.
result <- run_aggregate_dcea( icer = 25000, inc_qaly = 0.5, inc_cost = 12500, population_size = 10000, wtp = 20000 ) plot_ede_profile(result)result <- run_aggregate_dcea( icer = 25000, inc_qaly = 0.5, inc_cost = 12500, population_size = 10000, wtp = 20000 ) plot_ede_profile(result)
Creates the equity-efficiency impact plane as described in Cookson et al. (2017) Value in Health. The x-axis shows health inequality impact (change in a chosen inequality index), the y-axis shows net health benefit (efficiency). Four quadrants represent: Win-Win (NE), equity gain and efficiency loss (NW), equity loss and efficiency gain (SE), Lose-Lose (SW).
plot_equity_impact_plane( dcea_result, comparators = NULL, x_axis = "sii_change", y_axis = "nhb", show_psa_cloud = TRUE, show_quadrant_labels = TRUE, show_threshold_lines = TRUE, point_labels = NULL, colour_palette = NULL, theme_style = "publication" )plot_equity_impact_plane( dcea_result, comparators = NULL, x_axis = "sii_change", y_axis = "nhb", show_psa_cloud = TRUE, show_quadrant_labels = TRUE, show_threshold_lines = TRUE, point_labels = NULL, colour_palette = NULL, theme_style = "publication" )
dcea_result |
Object of class |
comparators |
Optional list of additional DCEA result objects to overlay on the same plane (for multi-comparator plots). |
x_axis |
Inequality metric for x-axis. One of |
y_axis |
Health outcome for y-axis. One of |
show_psa_cloud |
Logical. Show probabilistic scatter cloud if PSA
data are available (default: |
show_quadrant_labels |
Logical (default: |
show_threshold_lines |
Logical. Show NHB = 0 and inequality = 0
reference lines (default: |
point_labels |
Optional character vector of labels for points. |
colour_palette |
Optional named character vector of hex colours. |
theme_style |
Visual theme: |
A ggplot2 object.
Cookson R, Asaria M, Ali S, Shaw R, Doran T, Goldblatt P (2017). Health equity monitoring for healthcare quality assurance. Social Science & Medicine 198: 148-156.
result <- run_aggregate_dcea( icer = 25000, inc_qaly = 0.5, inc_cost = 12500, population_size = 10000, wtp = 20000 ) plot_equity_impact_plane(result)result <- run_aggregate_dcea( icer = 25000, inc_qaly = 0.5, inc_cost = 12500, population_size = 10000, wtp = 20000 ) plot_equity_impact_plane(result)
Visualises the causal pathway from intervention access to health inequality impact across the five staircase steps: (1) disease prevalence by group, (2) eligibility, (3) uptake/access, (4) clinical effect, (5) opportunity cost distribution.
plot_inequality_staircase(staircase_data, equity_var = "imd_quintile")plot_inequality_staircase(staircase_data, equity_var = "imd_quintile")
staircase_data |
Data frame with columns: |
equity_var |
Equity stratification variable name (for axis label). |
A ggplot2 faceted plot.
staircase_df <- data.frame( step = rep(1:5, each = 5), step_label = rep(c("Prevalence", "Eligibility", "Uptake", "Clinical effect", "Opportunity cost"), each = 5), group = rep(1:5, times = 5), group_label = rep(paste("Q", 1:5), times = 5), value = c(0.30, 0.28, 0.25, 0.22, 0.18, 0.90, 0.88, 0.85, 0.82, 0.80, 0.70, 0.65, 0.60, 0.55, 0.50, 0.45, 0.44, 0.43, 0.42, 0.40, 0.20, 0.18, 0.17, 0.15, 0.12) ) plot_inequality_staircase(staircase_df)staircase_df <- data.frame( step = rep(1:5, each = 5), step_label = rep(c("Prevalence", "Eligibility", "Uptake", "Clinical effect", "Opportunity cost"), each = 5), group = rep(1:5, times = 5), group_label = rep(paste("Q", 1:5), times = 5), value = c(0.30, 0.28, 0.25, 0.22, 0.18, 0.90, 0.88, 0.85, 0.82, 0.80, 0.70, 0.65, 0.60, 0.55, 0.50, 0.45, 0.44, 0.43, 0.42, 0.40, 0.20, 0.18, 0.17, 0.15, 0.12) ) plot_inequality_staircase(staircase_df)
Plots the Lorenz curve showing health concentration across the socioeconomic distribution. The 45-degree line represents perfect equality.
plot_lorenz_curve(dcea_result, show_pre_post = TRUE, show_generalised = FALSE)plot_lorenz_curve(dcea_result, show_pre_post = TRUE, show_generalised = FALSE)
dcea_result |
DCEA result object, or a data frame with health and weight columns. |
show_pre_post |
Logical. Overlay pre- and post-intervention curves
(default: |
show_generalised |
Logical. Overlay the Generalised Lorenz Curve
(default: |
A ggplot2 object.
result <- run_aggregate_dcea( icer = 25000, inc_qaly = 0.5, inc_cost = 12500, population_size = 10000, wtp = 20000 ) plot_lorenz_curve(result)result <- run_aggregate_dcea( icer = 25000, inc_qaly = 0.5, inc_cost = 12500, population_size = 10000, wtp = 20000 ) plot_lorenz_curve(result)
Dispatches to plot_equity_impact_plane by default.
## S3 method for class 'aggregate_dcea' plot(x, type = "impact_plane", ...)## S3 method for class 'aggregate_dcea' plot(x, type = "impact_plane", ...)
x |
An object of class |
type |
Plot type: |
... |
Additional arguments passed to the underlying plot function. |
A ggplot2 object.
Plot method for full_dcea
## S3 method for class 'full_dcea' plot(x, type = "impact_plane", ...)## S3 method for class 'full_dcea' plot(x, type = "impact_plane", ...)
x |
An object of class |
type |
Plot type (default |
... |
Additional arguments passed to the underlying plot function. |
A ggplot2 object.
Validates and standardises a data frame of subgroup-specific CEA results
for use in run_full_dcea.
prepare_subgroup_cea( data, group_var, inc_qaly_var, inc_cost_var, pop_share_var )prepare_subgroup_cea( data, group_var, inc_qaly_var, inc_cost_var, pop_share_var )
data |
Data frame with per-subgroup CEA results. |
group_var |
Name of the group identifier column. |
inc_qaly_var |
Name of the incremental QALY column. |
inc_cost_var |
Name of the incremental cost column. |
pop_share_var |
Name of the population share column. |
A validated and normalised tibble.
df <- tibble::tibble( group = 1:5, inc_qaly = c(0.3, 0.4, 0.5, 0.55, 0.6), inc_cost = rep(10000, 5), pop_share = rep(0.2, 5) ) prepare_subgroup_cea(df, "group", "inc_qaly", "inc_cost", "pop_share")df <- tibble::tibble( group = 1:5, inc_qaly = c(0.3, 0.4, 0.5, 0.55, 0.6), inc_cost = rep(10000, 5), pop_share = rep(0.2, 5) ) prepare_subgroup_cea(df, "group", "inc_qaly", "inc_cost", "pop_share")
Print method for aggregate_dcea
## S3 method for class 'aggregate_dcea' print(x, ...)## S3 method for class 'aggregate_dcea' print(x, ...)
x |
An object of class |
... |
Further arguments (ignored). |
Invisibly returns x.
Print method for full_dcea
## S3 method for class 'full_dcea' print(x, ...)## S3 method for class 'full_dcea' print(x, ...)
x |
An object of class |
... |
Further arguments (ignored). |
Invisibly returns x.
Implements the aggregate DCEA approach of Love-Koh et al. (2019) Value in Health. Uses disease-level healthcare utilisation patterns to distribute average health benefits from a standard CEA across socioeconomic groups. This is the method supported by NICE (2025) as a supplementary analysis for technology appraisals.
run_aggregate_dcea( icer, inc_qaly, inc_cost, population_size, wtp = 20000, disease_icd = NULL, subgroup_distribution = NULL, baseline_health = NULL, equity_var = "imd_quintile", wtp_for_equity = NULL, opportunity_cost_threshold = 13000, psa_results = NULL )run_aggregate_dcea( icer, inc_qaly, inc_cost, population_size, wtp = 20000, disease_icd = NULL, subgroup_distribution = NULL, baseline_health = NULL, equity_var = "imd_quintile", wtp_for_equity = NULL, opportunity_cost_threshold = 13000, psa_results = NULL )
icer |
Incremental cost-effectiveness ratio (GBP per QALY). |
inc_qaly |
Incremental QALYs per patient (from base-case CEA). |
inc_cost |
Incremental cost per patient (from base-case CEA). |
population_size |
Total eligible population size (integer). |
wtp |
Willingness-to-pay threshold in GBP/QALY (default: 20000). |
disease_icd |
ICD-10 code or description for HES utilisation lookup.
Used to distribute benefits across IMD groups if |
subgroup_distribution |
Optional named numeric vector (length = number
of equity subgroups) giving the proportion of patients in each group.
Names should match group labels in the baseline dataset. Must sum to 1.
If |
baseline_health |
Optional tibble from |
equity_var |
Equity stratification variable (default:
|
wtp_for_equity |
Optional second WTP threshold for equity-weighted analysis. |
opportunity_cost_threshold |
Cost per QALY of care displaced by the intervention's budget impact (default: 13000, i.e., NICE's k threshold). |
psa_results |
Optional data frame of PSA iteration results (one row
per iteration, columns |
An object of class "aggregate_dcea", a named list with:
summaryKey scalar DCEA outputs.
by_groupPer-group tibble: health gain, opportunity cost, NHB.
inequality_impactPre/post inequality indices.
social_welfareSocial welfare results over eta.
equity_plane_dataData frame for plot_equity_impact_plane.
metadataInputs and assumptions.
Love-Koh J, Asaria M, Cookson R, Griffin S (2019). The Social Distribution of Health: Estimating Quality-Adjusted Life Expectancy in England. Value in Health 22(5): 518-526. doi:10.1016/j.jval.2018.10.007
plot_equity_impact_plane, run_full_dcea
result <- run_aggregate_dcea( icer = 25000, inc_qaly = 0.5, inc_cost = 12500, population_size = 10000, wtp = 20000 ) summary(result)result <- run_aggregate_dcea( icer = 25000, inc_qaly = 0.5, inc_cost = 12500, population_size = 10000, wtp = 20000 ) summary(result)
Performs systematic one-way and multi-way sensitivity analysis across
key DCEA parameters: inequality aversion (), WTP threshold,
opportunity cost threshold, subgroup distribution assumptions, and equity
measure choice.
run_dcea_sensitivity( dcea_result, params_to_vary = "all", eta_range = 0:10, wtp_range = NULL, occ_range = NULL )run_dcea_sensitivity( dcea_result, params_to_vary = "all", eta_range = 0:10, wtp_range = NULL, occ_range = NULL )
dcea_result |
Object of class |
params_to_vary |
Character vector of parameter names to vary. Options:
|
eta_range |
Numeric vector of |
wtp_range |
Numeric vector of WTP values to test (default: varies ±50% around base case). |
occ_range |
Numeric vector of opportunity cost threshold values
(default: |
An object of class "dcea_sensitivity" with elements:
eta_profileTibble: NHB and SII change across eta range.
one_wayTibble: results of one-way sensitivity for all parameters.
tornado_dataData frame ready for tornado plot.
parametersList of parameter ranges used.
result <- run_aggregate_dcea( icer = 25000, inc_qaly = 0.5, inc_cost = 12500, population_size = 10000, wtp = 20000 ) sa <- run_dcea_sensitivity(result, params_to_vary = "eta") plot_dcea_tornado(sa)result <- run_aggregate_dcea( icer = 25000, inc_qaly = 0.5, inc_cost = 12500, population_size = 10000, wtp = 20000 ) sa <- run_dcea_sensitivity(result, params_to_vary = "eta") plot_dcea_tornado(sa)
Implements full-form DCEA where subgroup-specific model parameters are available (e.g., differential uptake, differential quality-of-life gains, differential survival by socioeconomic group). Full-form DCEA is appropriate when:
The disease has well-documented SES gradients in clinical outcomes.
Subgroup trial data or real-world evidence is available.
NICE requires more granular equity evidence (HST or exceptional cases).
run_full_dcea( subgroup_cea_results, baseline_health, wtp = 20000, opportunity_cost_threshold = 13000, uptake_by_group = NULL, adherence_by_group = NULL, comorbidity_adjustment = FALSE, psa_iterations = NULL )run_full_dcea( subgroup_cea_results, baseline_health, wtp = 20000, opportunity_cost_threshold = 13000, uptake_by_group = NULL, adherence_by_group = NULL, comorbidity_adjustment = FALSE, psa_iterations = NULL )
subgroup_cea_results |
Data frame with one row per equity subgroup.
Required columns: |
baseline_health |
Tibble from |
wtp |
Willingness-to-pay threshold in GBP/QALY (default: 20000). |
opportunity_cost_threshold |
Cost per QALY of displaced care (default: 13000). |
uptake_by_group |
Optional named numeric vector of uptake rates (0-1)
per group. If |
adherence_by_group |
Optional named numeric vector of adherence rates
(0-1) per group. Applied as a multiplier on |
comorbidity_adjustment |
Logical. If |
psa_iterations |
Optional integer. Number of PSA iterations. If provided, returns probabilistic NHB distribution by group. |
An object of class "full_dcea" with elements analogous to
run_aggregate_dcea plus subgroup-level detail.
baseline <- get_baseline_health("england", "imd_quintile") subgroup_data <- tibble::tibble( group = 1:5, group_label = paste("IMD Q", 1:5), inc_qaly = c(0.30, 0.38, 0.45, 0.52, 0.58), inc_cost = c(12000, 11500, 11000, 10500, 10000), pop_share = rep(0.2, 5) ) result <- run_full_dcea(subgroup_data, baseline) summary(result)baseline <- get_baseline_health("england", "imd_quintile") subgroup_data <- tibble::tibble( group = 1:5, group_label = paste("IMD Q", 1:5), inc_qaly = c(0.30, 0.38, 0.45, 0.52, 0.58), inc_cost = c(12000, 11500, 11000, 10500, 10000), pop_share = rep(0.2, 5) ) result <- run_full_dcea(subgroup_data, baseline) summary(result)
Summary method for aggregate_dcea
## S3 method for class 'aggregate_dcea' summary(object, ...)## S3 method for class 'aggregate_dcea' summary(object, ...)
object |
An object of class |
... |
Further arguments (ignored). |
A tibble of key DCEA outputs.
Summary method for full_dcea
## S3 method for class 'full_dcea' summary(object, ...)## S3 method for class 'full_dcea' summary(object, ...)
object |
An object of class |
... |
Further arguments (ignored). |
Invisibly returns object.
Checks that a data frame has required columns, correct types, and that population weights sum to 1. Returns the data frame invisibly if valid, or throws an informative error.
validate_dcea_data(data, required_cols, weight_var, tol = 1e-06)validate_dcea_data(data, required_cols, weight_var, tol = 1e-06)
data |
A data frame to validate. |
required_cols |
Character vector of required column names. |
weight_var |
Name of the population weight column. |
tol |
Tolerance for checking that weights sum to 1 (default: 1e-6). |
The input data frame, invisibly.
df <- tibble::tibble( group = 1:5, mean_hale = c(60, 63, 66, 69, 72), pop_share = rep(0.2, 5) ) validate_dcea_data(df, c("group", "mean_hale", "pop_share"), "pop_share")df <- tibble::tibble( group = 1:5, mean_hale = c(60, 63, 66, 69, 72), pop_share = rep(0.2, 5) ) validate_dcea_data(df, c("group", "mean_hale", "pop_share"), "pop_share")
Health-Adjusted Life Expectancy at birth for the six WHO regions. Useful for international equity analyses and global burden of disease perspectives.
who_regions_halewho_regions_hale
A tibble with 6 rows and 8 variables:
Character. WHO region code.
Character. Full region name.
Numeric. HALE at birth (years).
Numeric. Standard error.
Numeric. Proportion of world population.
Numeric. Ridit score.
Integer. Reference year.
Character. WHO GHO data citation.
WHO Global Health Observatory. https://www.who.int/data/gho