| Title: | Evaluates Present Values and Health Economic Models with Dynamic Pricing and Uptake |
|---|---|
| Description: | The goal of 'dynamicpv' is to provide a simple way to calculate (net) present values and outputs from health economic models (especially cost-effectiveness and budget impact) in discrete time that reflect dynamic pricing and dynamic uptake. Dynamic pricing is also known as life cycle pricing; dynamic uptake is also known as multiple or stacked cohorts, or dynamic disease prevalence. Shafrin (2024) <doi:10.1515/fhep-2024-0014> provides an explanation of dynamic value elements, in the context of Generalized Cost Effectiveness Analysis, and Puls (2024) <doi:10.1016/j.jval.2024.03.006> reviews challenges of incorporating such dynamic value elements. This package aims to reduce those challenges. |
| Authors: | Dominic Muston [aut, cre] (ORCID: <https://orcid.org/0000-0003-4876-7940>), John Blischak [ctb] (ORCID: <https://orcid.org/0000-0003-2634-9879>), Merck & Co., Inc., Rahway, NJ, USA and its affiliates [cph, fnd] |
| Maintainer: | Dominic Muston <[email protected]> |
| License: | GPL (>= 3) |
| Version: | 0.4.2 |
| Built: | 2026-06-03 08:07:14 UTC |
| Source: | https://github.com/msdllcpapers/dynamicpv |
Subtract one object of S7 class "dynpv" from another
## S3 method for class 'dynpv' e1 - e2## S3 method for class 'dynpv' e1 - e2
e1 |
First "dynpv" object |
e2 |
Second "dynpv" object |
Present value of e1-e2 is the present values from e1 less that from e2.
Total uptake of e1-e2 is the uptake from e1 less that from e2. Take
care of this when using $mean of the summed object.
S3 object of class "dynpv"
Add together two objects each of class "dynpv"
## S3 method for class 'dynpv' e1 + e2## S3 method for class 'dynpv' e1 + e2
e1 |
First "dynpv" object |
e2 |
Second "dynpv" object |
S3 object of class "dynpv"
Add together two objects each of S3 class "dynpv": e1 + mult * e2
addprod(e1, e2, mult)addprod(e1, e2, mult)
e1 |
First "dynpv" object |
e2 |
Second "dynpv" object |
mult |
Numeric Present value is present value from |
S3 object of class "dynpv"
Calculate present value for a payoff with dynamic (lifecycle) pricing and dynamic uptake (stacked cohorts).
dynpv( uptakes = 1, payoffs, horizon = length(payoffs), tzero = 0, prices = rep(1, length(payoffs) + tzero), discrate = 0 )dynpv( uptakes = 1, payoffs, horizon = length(payoffs), tzero = 0, prices = rep(1, length(payoffs) + tzero), discrate = 0 )
uptakes |
Vector of patient uptake over time |
payoffs |
Vector of payoffs of interest (numeric vector) |
horizon |
Time horizon for the calculation (length must be less than or equal to the length of payoffs) |
tzero |
Time at the date of calculation, to be used in lookup in prices vector |
prices |
Vector of price indices through the time horizon of interest |
discrate |
Discount rate per timestep, corresponding to price index |
Suppose payoffs in relation to patients receiving treatment (such as costs or health outcomes) occur over timesteps . Let us partition time as follows.
Suppose indexes the time at which the patient begins treatment.
Suppose indexes time since initiating treatment.
In general, , and we are interested in the set of such that .
For example, comprises:
patients who are in the third timestep of treatment that began in timestep 1: (j,k)=(1,3);
patients who are in the second timestep of treatment that began in timestep 2, (j,k)=(2,2); and
patients who are in the first timestep of treatment that began in timestep 3, (j,k)=(3,1)
The Present Value of a cashflow for the patients who began treatment at time and who are in their th timestep of treatment is as follows
where is the risk-free discount rate per timestep, is the cashflow amount in today’s money, and is the nominal amount of the cashflow at the time it is incurred, allowing for an offset of .
The total present value, , is therefore the sum over all and within the time horizon , namely:
This function calculates for all values of , and , and returns this in a tibble.
A tibble of class "dynpv" with the following columns:
j: Time at which patients began treatment
k: Time since patients began treatment
l: Time offset for the price index (from tzero)
t: Equals
uj: Uptake of patients beginning treatment at time (from uptakes)
pk: Cashflow amount in today's money in respect of patients at time since starting treatment (from payoffs)
R: Index of prices over time (from prices)
v: Discounting factors, , where i is the discount rate per timestep
pv: Present value,
# Simple example pv1 <- dynpv( uptakes = (1:10), # 1 patient uptakes in timestep 1, 2 patients in timestep 2, etc tzero = c(0,5), # Calculations are performed with prices at times 0 and 5 payoffs = 90 + 10*(1:10), # Payoff vector of length 10 = (100, 110, ..., 190) prices = 1.02^((1:15)-1), # Prices increase at 2\% per timestep in future discrate = 0.05 # The nominal discount rate is 5\% per timestep; # the real discount rate per timestep is 3\% (=5\% - 3\%) ) pv1 summary(pv1) # More complex example, using cashflow output from a heemod model # Obtain dataset democe <- get_dynfields( heemodel = oncpsm, payoffs = c("cost_daq_new", "cost_total", "qaly"), discount = "disc" ) # Obtain short payoff vector of interest payoffs <- democe |> dplyr::filter(int=="new", model_time<11) |> dplyr::mutate(cost_oth = cost_total - cost_daq_new) # Example calculation pv2 <- dynpv( uptakes = rep(1, nrow(payoffs)), payoffs = payoffs$cost_oth, prices = 1.05^(0:(nrow(payoffs)-1)), discrate = 0.08 ) summary(pv2)# Simple example pv1 <- dynpv( uptakes = (1:10), # 1 patient uptakes in timestep 1, 2 patients in timestep 2, etc tzero = c(0,5), # Calculations are performed with prices at times 0 and 5 payoffs = 90 + 10*(1:10), # Payoff vector of length 10 = (100, 110, ..., 190) prices = 1.02^((1:15)-1), # Prices increase at 2\% per timestep in future discrate = 0.05 # The nominal discount rate is 5\% per timestep; # the real discount rate per timestep is 3\% (=5\% - 3\%) ) pv1 summary(pv1) # More complex example, using cashflow output from a heemod model # Obtain dataset democe <- get_dynfields( heemodel = oncpsm, payoffs = c("cost_daq_new", "cost_total", "qaly"), discount = "disc" ) # Obtain short payoff vector of interest payoffs <- democe |> dplyr::filter(int=="new", model_time<11) |> dplyr::mutate(cost_oth = cost_total - cost_daq_new) # Example calculation pv2 <- dynpv( uptakes = rep(1, nrow(payoffs)), payoffs = payoffs$cost_oth, prices = 1.05^(0:(nrow(payoffs)-1)), discrate = 0.08 ) summary(pv2)
Present value of a series of payoffs for a single given cohort, entering at given future time, allowing for dynamic pricing. This function is a wrapper for dynpv() restricted to evaluation of a single cohort.
futurepv(tzero = 0, payoffs, prices, discrate)futurepv(tzero = 0, payoffs, prices, discrate)
tzero |
Time at the date of calculation, to be used in lookup in prices vector |
payoffs |
Vector of payoffs of interest (numeric vector) |
prices |
Vector of price indices through the time horizon of interest |
discrate |
Discount rate per timestep, corresponding to price index |
A tibble of class "dynpv" with the following columns:
j: Time at which patients began treatment
k: Time since patients began treatment
l: Time offset for the price index (from tzero)
t: Equals
uj: Uptake of patients beginning treatment at time (from uptakes)
pk: Cashflow amount in today's money in respect of patients at time since starting treatment (from payoffs)
R: Index of prices over time (from prices)
v: Discounting factors, , where i is the discount rate per timestep
pv: Present value,
library(dplyr) # Obtain dataset democe <- get_dynfields( heemodel = oncpsm, payoffs = c("cost_daq_new", "cost_total", "qaly"), discount = "disc" ) # Obtain discount rate discrate <- get_param_value(oncpsm, "disc") # Obtain payoff vector of interest payoffs <- democe |> filter(int=="new") |> mutate(cost_oth_rup = cost_total_rup - cost_daq_new_rup) Nt <- nrow(payoffs) # Run calculation for times 0-9 fpv <- futurepv( tzero = (0:9)*52, payoffs = payoffs$cost_oth_rup, prices = 1.001^(1:(2*Nt)-1), # Approx 5.3% every 52 steps discrate = 0.001 + discrate ) fpv summary(fpv)library(dplyr) # Obtain dataset democe <- get_dynfields( heemodel = oncpsm, payoffs = c("cost_daq_new", "cost_total", "qaly"), discount = "disc" ) # Obtain discount rate discrate <- get_param_value(oncpsm, "disc") # Obtain payoff vector of interest payoffs <- democe |> filter(int=="new") |> mutate(cost_oth_rup = cost_total_rup - cost_daq_new_rup) Nt <- nrow(payoffs) # Run calculation for times 0-9 fpv <- futurepv( tzero = (0:9)*52, payoffs = payoffs$cost_oth_rup, prices = 1.001^(1:(2*Nt)-1), # Approx 5.3% every 52 steps discrate = 0.001 + discrate ) fpv summary(fpv)
Helper function to get a tibble of the relevant fields from heemod output
get_dynfields(heemodel, payoffs, discount, fname = NA)get_dynfields(heemodel, payoffs, discount, fname = NA)
heemodel |
A health economic model object from the heemod package (see heemod::heemod-package). |
payoffs |
Field names of payoffs of interest (string vector) |
discount |
Name of parameter providing discount rate per cycle (string) |
fname |
Export data to a .CSV file of this name, if given (character) |
Tibble of payoffs taken from the heemod model, by intervention and model timestep (model_time).
The field vt is calculated as (1+i)^(1-model_time), where i is the discount rate per model timestep set in the heemod model through the parameter disc_cycle. This can be useful in 'rolling-up' payoff values to the timestep in which they were incurred.
An additional set of payoffs (identified with a "_rup" suffix) provides calculations of the payoffs as at the start of the timestep in which they were incurred, i.e. original payoff / vt.
democe <- get_dynfields( heemodel = oncpsm, payoffs = c("cost_daq_new", "cost_total", "qaly"), discount = "disc" ) head(democe)democe <- get_dynfields( heemodel = oncpsm, payoffs = c("cost_daq_new", "cost_total", "qaly"), discount = "disc" ) head(democe)
Obtain parameter value(s) from a heemod output
get_param_value(heemodel, param)get_param_value(heemodel, param)
heemodel |
A health economic model object from the heemod package (see heemod::heemod-package). |
param |
Name of parameter to extract from the heemod model |
Value of the parameter from the heemod model
get_param_value( heemodel = oncpsm, param = "disc" )get_param_value( heemodel = oncpsm, param = "disc" )
Mean of the Present Value per uptaking patient, by time at which the calculation is performed (tzero input to dynpv()).
## S3 method for class 'dynpv' mean(x, ...)## S3 method for class 'dynpv' mean(x, ...)
x |
Tibble of class "dynpv" created by |
... |
Currently unused |
This is equal to total() divided by uptake().
A number or tibble
Number of cohorts of uptaking patients, calculated as the length of the uptakes input to dynpv()
ncoh(df)ncoh(df)
df |
Tibble of class "dynpv" created by |
A number
Number of times at which present value calculations are performed, calculated as the length of the tzero input to dynpv()
ntimes(df)ntimes(df)
df |
Tibble of class "dynpv" created by |
A number
An example three state cost-effectiveness model in oncology built using heemod::heemod-package() according to the assumptions and specification in the accompanying paper.
oncpsmoncpsm
oncpsmA heemod object
Created based on assumptions.
Calculates the sum of the Present Value by uptake cohort (j) and time at which the calculation is performed (tzero input to dynpv())
sum_by_coh(df)sum_by_coh(df)
df |
Tibble of class "dynpv" created by |
The Present Value of a cashflow for the patients who began treatment at time and who are in their th timestep of treatment is as follows
where is the risk-free discount rate per timestep, is the cashflow amount in today’s money, and is the nominal amount of the cashflow at the time it is incurred, allowing for an offset of .
This method returns for each value of and , where is the time horizon of the calculation.
A number or tibble
Summarize a dynpv object
## S3 method for class 'dynpv' summary(object, ...)## S3 method for class 'dynpv' summary(object, ...)
object |
Tibble of class "dynpv" created by |
... |
Currently unused |
A list of class "dynpv_summary" with the following elements:
ncoh: Number of cohorts of uptaking patients, from ncoh()
ntimes: Number of times at which present value calculations are performed, from ntimes()
uptake: Total number of uptaking patients, from uptake()
sum_by_coh: Present value for each uptake cohort and calculation time, from sum_by_coh()
total: Total present value, from total()
mean: Mean present value per uptaking patient, from mean(), equal to total/uptake.
Sum of the Present Value, by time at which the calculation is performed (tzero input to dynpv())
total(df)total(df)
df |
Tibble of class "dynpv" created by |
The Present Value of a cashflow for the patients who began treatment at time and who are in their th timestep of treatment is as follows
where is the risk-free discount rate per timestep, is the cashflow amount in today’s money, and is the nominal amount of the cashflow at the time it is incurred, allowing for an offset of .
The total present value by time at which the calculation is performed, , is therefore the sum of over all and within the time horizon , namely:
A number or tibble
Trim the tailing zeroes from a long vector
trim_vec(vec)trim_vec(vec)
vec |
Vector. Final elements may be zero. |
A vector whose length is shorter than the original, if there were trailing zero elements
trim_vec(c(1:10, rep(0,3)))trim_vec(c(1:10, rep(0,3)))
Total number of uptaking patients, calculated as the sum of the uptake input to dynpv(), or
uptake(df)uptake(df)
df |
Tibble of class "dynpv" created by |
A number or tibble