Cost-effectiveness analysis (CEA) is one form of economic evaluation that compares the cost, effectiveness, and efficiency of a set of mutually exclusive strategies in generating desired benefits. The goal of cost-effectiveness is to identify the strategy that yields that greatest benefit at an acceptable level of efficiency. Effectiveness is often measured in terms of quality-adjusted life-years (QALYs); however, life-years, infections/cases averted, or other measures of benefit could be used, depending on the goals of the decision maker. Costs reflect the cost of implementing the strategy, as well as any relevant downstream costs. The determination of which costs to include depends on the perspective of the analysis. For a more in-depth explanation of cost-effectiveness analysis, see:
Given a set of mutually exclusive strategies with associated costs and effectiveness, the first step in determining cost-effectiveness is to order strategies in order of increasing costs. As costs increase, effectiveness should also increase. Any strategy with lower effectiveness but higher costs than another strategy is said to be “strongly dominated”. A rational decision-maker would never implement a dominated strategy because greater effectiveness could be achieved at lower cost by implementing a different strategy (and the strategies are mutually exclusive). Therefore, dominated strategies are eliminated from further consideration.
Next, the incremental cost and incremental effectiveness of moving from one strategy to the next (in order of increasing costs) are calculated. The incremental cost-effectiveness ratio (ICER) for each strategy is then its incremental costs divided by its incremental effectiveness and represents the cost per unit benefit of “upgrading” to that strategy from the next least costly (and next least effective) strategy. At this point, “weakly dominated” strategies are identified. These are strategies for which there is a linear combination of two different strategies that dominates the strategy (lower costs and/or higher effectiveness). Weak dominance is also called “extended dominance”. Operationally, weakly dominated strategies can be identified by checking that ICERs increase with increasingly costly (and effective) strategies. If there is a “kink” in the trend, then weak/extended dominance exists. Once weakly dominated strategies are removed (and incremental quantities recalculated), the set of remaining strategies form the efficient frontier and associated ICERs can be interpreted for decision-making.
The dampack
function calculate_icers()
completes all of the calculations and checks described above. It takes as inputs the cost, effectiveness outcome (usually QALYs), and strategy name for each strategy, passed as separate vectors. It outputs a specialized data frame that presents the costs and effectiveness of each strategy and, for non-dominated strategies, the incremental costs, effectiveness, and ICER. Dominated strategies are included at the end of the table with the type of dominance indicated as either strong dominance (D) or extended/weak dominance (ED) in the Status
column.
We present the application of calculate_icers()
in the two examples below.
From: Paltiel AD, Walensky RP, Schackman BR, Seage GR, Mercincavage LM, Weinstein MC, Freedberg KA. Expanded HIV screening in the United States: effect on clinical outcomes, HIV transmission, and costs. Annals of Internal Medicine. 2006;145(11): 797-806. https://doi.org/10.7326/0003-4819-145-11-200612050-00004.
In this example, a model was used to assess the costs, benefits, and cost-effectiveness of different HIV screening frequencies in different populations with different HIV prevalence and incidence. To illustrate the CEA functionality of dampack
, we will focus on the results evaluating HIV screening frequencies in a high-risk population (1.0% prevalence, 0.12% annual incidence) and accounting only for patient-level benefits (i.e., ignoring any reduction in secondary HIV transmission).
Five strategies are considered: No specific screening recommendation (status quo), one-time HIV test, HIV testing every 5 years, HIV testing every 3 years, and HIV test annually.
We define a vector of short strategy names, which will be used in labeling our results in the tables and plots.
library(dampack)
#> Loading required package: ggplot2
<- c("status quo", "one time", "5yr", "3yr", "annual") v_hiv_strat_names
Costs for each strategy included the cost of the screening strategy and lifetime downstream medical costs for the population. These are presented as the average cost per person in Table 4 of Paltiel et al. 2006. We store the cost of each strategy in a vector (in the same order as in v_strat_names
).
<- c(26000, 27000, 28020, 28440, 29440) v_hiv_costs
The effectiveness of each strategy was measured in terms of quality-adjusted life-expectancy of the population, which captures both length of life and quality of life. This was reported in terms of quality-adjusted life-months in Table 4 in Paltiel et al. 2006, which we convert to quality-adjusted life-years (QALYs) by dividing by 12.
<- c(277.25, 277.57, 277.78, 277.83, 277.76) / 12 v_hiv_qalys
Using these elements, we then use the calculate_icers()
function in dampack
to conduct the cost-effectiveness comparison of the five HIV testing strategies.
<- calculate_icers(cost=v_hiv_costs,
icer_hiv effect=v_hiv_qalys,
strategies=v_hiv_strat_names)
icer_hiv#> Strategy Cost Effect Inc_Cost Inc_Effect ICER Status
#> 1 status quo 26000 23.10417 NA NA NA ND
#> 2 one time 27000 23.13083 1000 0.026666667 37500.00 ND
#> 3 5yr 28020 23.14833 1020 0.017500000 58285.71 ND
#> 4 3yr 28440 23.15250 420 0.004166667 100800.00 ND
#> 5 annual 29440 23.14667 NA NA NA D
The resulting output icer_hiv
is an icer
object (unique to dampack
) to facilitate visualization, but it can also be manipulated like a data frame. The default view is ordered by dominance status (ND = non-dominated, ED = extended/weak dominance, or D= strong dominance), and then ascending by cost. In our example, like in Paltiel et al. 2006, we see that the annual screening strategy is strongly dominated, though the ICERs calculated here are slightly different from those in the published article due to rounding in the reporting of costs and effectiveness.
The icer
object can be easily formatted into a publication quality table using the kableExtra
package.
library(kableExtra)
library(dplyr)
%>%
icer_hiv kable() %>%
kable_styling()
Strategy | Cost | Effect | Inc_Cost | Inc_Effect | ICER | Status |
---|---|---|---|---|---|---|
status quo | 26000 | 23.10417 | NA | NA | NA | ND |
one time | 27000 | 23.13083 | 1000 | 0.0266667 | 37500.00 | ND |
5yr | 28020 | 23.14833 | 1020 | 0.0175000 | 58285.71 | ND |
3yr | 28440 | 23.15250 | 420 | 0.0041667 | 100800.00 | ND |
annual | 29440 | 23.14667 | NA | NA | NA | D |
The results contained in icer_hiv
can be visualized in the cost-effectiveness plane using the plot()
function, which has its own method for the icer
object class.
plot(icer_hiv)
In the plot, the points on the efficient frontier (consisting of all non-dominated strategies) are connected with a solid line. By default, only strategies on the efficient frontier are labeled. However, this can be changed by setting label="all"
. There are a number of built-in options for customizing the cost-effectiveness plot. To see a full listing, type ?plot.icers
in the console. Furthermore, the plot of an icer
object is a ggplot
object, so we can add (+
) any of the normal ggplot adjustments to the plot. To do this, ggplot2
needs to be loaded with library()
. A introduction to ggplot2 is available at https://ggplot2.tidyverse.org/ .
Plot with all strategies labeled:
plot(icer_hiv,
label="all")
Plot with a different ggplot
theme:
plot(icer_hiv,
label="all") +
theme_classic() +
ggtitle("Cost-effectiveness of HIV screening strategies")
From: Rajasingham R, Enns EA, Khoruts A, Vaughn BP. Cost-effectiveness of Treatment Regimens for Clostridioides difficile Infection: An Evaluation of the 2018 Infectious Diseases Society of America Guidelines. Clinical Infectious Diseases. 2020;70(5):754-762. https://doi.org/10.1093/cid/ciz318
In this example, we use a probabilistic sensitivity analysis (PSA) as the basis of our cost-effectiveness calculations, as is now recommended by the Second Panel on Cost-Effectiveness in Health and Medicine (Neumann et al. 2016). For more explanation about PSA and its generation process, please see our PSA vignette by typing vignette("psa_generation", package = "dampack")
in the console after installing the dampack
package. The PSA dataset in this example was conducted for a model of Clostridioides difficile (C. diff) infection that compared 48 possible treatment strategies, which varied in the treatment regimen used for initial versus recurrent CDI and for different infection severities. For didactic purposes, we have reduced the set of strategies down to the 11 most-relevant strategies; however, in a full CEA, all feasible strategies should be considered (as they are in Rajasingam et al. 2020).
Costs in this example include all treatment costs and lifetime downstream medical costs. Strategy effectiveness was measured in terms of quality-adjusted life-expectancy. Outcomes were evaluated for a 67-year-old patient, which is the median age of C. diff infection patients.
The C. diff PSA dataset is provided within dampack
and can be accessed using the data()
function.
library(dampack)
data("psa_cdiff")
This creates the object cdiff_psa
which is a psa
object class (specific to dampack
), sharing some properties with data frames. For more information on the properties of psa
objects, please see vignette("psa_analysis", package = "dampack")
. To use calculate_icers()
, we first need to calculate the average cost and average effectiveness for each strategy across the PSA samples. To do this, we use summary()
, which has its own specific method for psa
objects that calculates the mean of each outcome over the PSA samples. For more information, type ?summary.psa
in the console.
<- summary(psa_cdiff)
df_cdiff_ce head(df_cdiff_ce)
#> Strategy meanCost meanEffect
#> 1 s3 57336.01 12.93996
#> 2 s27 57541.25 13.01406
#> 3 s33 57642.26 13.03891
#> 4 s31 57934.07 13.09663
#> 5 s43 58072.11 13.11286
#> 6 s44 58665.78 13.12833
Here, strategies are just named with a number (e.g., “s3” or “s39”). The specifications of each strategy can be found in Rajasingam et al. 2020.
The df_cdiff_ce
object is a data frame containing the mean cost and mean effectiveness for each of our 11 strategies. We pass the columns of df_cdiff_ce
to the calculate_icers()
function to conduct our CEA comparisons.
<- calculate_icers(cost = df_cdiff_ce$meanCost,
icer_cdiff effect = df_cdiff_ce$meanEffect,
strategies = df_cdiff_ce$Strategy)
%>%
icer_cdiff kable() %>%
kable_styling()
Strategy | Cost | Effect | Inc_Cost | Inc_Effect | ICER | Status |
---|---|---|---|---|---|---|
s3 | 57336.01 | 12.93996 | NA | NA | NA | ND |
s27 | 57541.25 | 13.01406 | 205.2466 | 0.0741001 | 2769.855 | ND |
s33 | 57642.26 | 13.03891 | 101.0061 | 0.0248476 | 4065.031 | ND |
s31 | 57934.07 | 13.09663 | 291.8156 | 0.0577142 | 5056.222 | ND |
s43 | 58072.11 | 13.11286 | 138.0394 | 0.0162319 | 8504.216 | ND |
s44 | 58665.78 | 13.12833 | 593.6686 | 0.0154752 | 38362.652 | ND |
s39 | 57814.65 | 13.04628 | NA | NA | NA | ED |
s4 | 57887.48 | 12.99707 | NA | NA | NA | D |
s13 | 58018.63 | 13.06504 | NA | NA | NA | D |
s37 | 58081.79 | 13.10297 | NA | NA | NA | D |
s20 | 58634.20 | 13.11006 | NA | NA | NA | D |
In this example, 5 of the 11 strategies are dominated. Most are strongly dominated (denoted by “D”), while one is dominated through extended/weak dominance (denoted “ED”). When many dominated strategies are present in an analysis, it may be desirable to completely remove them from the CEA results table. This can be done by filtering by the Status
column to include only non-dominated strategies.
%>%
icer_cdiff filter(Status == "ND")%>%
kable() %>%
kable_styling()
Strategy | Cost | Effect | Inc_Cost | Inc_Effect | ICER | Status |
---|---|---|---|---|---|---|
s3 | 57336.01 | 12.93996 | NA | NA | NA | ND |
s27 | 57541.25 | 13.01406 | 205.2466 | 0.0741001 | 2769.855 | ND |
s33 | 57642.26 | 13.03891 | 101.0061 | 0.0248476 | 4065.031 | ND |
s31 | 57934.07 | 13.09663 | 291.8156 | 0.0577142 | 5056.222 | ND |
s43 | 58072.11 | 13.11286 | 138.0394 | 0.0162319 | 8504.216 | ND |
s44 | 58665.78 | 13.12833 | 593.6686 | 0.0154752 | 38362.652 | ND |
To visualize our results on the cost-effectiveness plane, we can use the plot()
function on icer_diff
(an icer
object).
plot(icer_cdiff)
In the plot, we can clearly see the one weakly dominated strategy that is more expensive and less beneficial than a linear combination of strategies “s3” and “s31” (a point on the line connecting these two strategies).
Here are some additional plotting options:
plot(icer_cdiff, label = "all") # can lead to a 'busy' plot
plot(icer_cdiff, plot_frontier_only = TRUE) # completely removes dominated strategies from plot
plot(icer_cdiff, currency = "USD", effect_units = "quality-adjusted life-years") # customize axis labels