Skip to content

Commit e2ae62b

Browse files
authored
Merge pull request #20 from jdblischak/simplify
Use a tibble/df as the primary object
2 parents 4ee7f54 + ffca698 commit e2ae62b

25 files changed

+542
-401
lines changed

.Rbuildignore

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
^dynacem\.Rproj$
1+
^dynamicpv\.Rproj$
22
^\.Rproj\.user$
33
^README\.Rmd$
44
^data-raw$
@@ -7,3 +7,8 @@
77
^doc$
88
^Meta$
99
^docs$
10+
^LICENSES-THIRD-PARTY\.md$
11+
^codecov\.yml$
12+
^pkg\.lock$
13+
^pkgdown$
14+
^sticker\.png$

NAMESPACE

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,30 @@
22

33
S3method("+",dynpv)
44
S3method("-",dynpv)
5-
S3method(print,dynpv)
5+
S3method(mean,dynpv)
6+
S3method(print,dynpv_summary)
7+
S3method(summary,dynpv)
68
export(addprod)
7-
export(class_dynpv)
89
export(dynpv)
910
export(futurepv)
1011
export(get_dynfields)
1112
export(get_param_value)
13+
export(ncoh)
14+
export(ntimes)
15+
export(sum_by_coh)
16+
export(total)
1217
export(trim_vec)
13-
importFrom(rlang,.data)
18+
export(uptake)
19+
importFrom(dplyr,across)
20+
importFrom(dplyr,all_of)
21+
importFrom(dplyr,as_tibble)
22+
importFrom(dplyr,bind_rows)
23+
importFrom(dplyr,filter)
24+
importFrom(dplyr,join_by)
25+
importFrom(dplyr,left_join)
26+
importFrom(dplyr,mutate)
27+
importFrom(dplyr,rename)
28+
importFrom(dplyr,select)
29+
importFrom(dplyr,summarize)
30+
importFrom(tidyr,expand_grid)
31+
importFrom(tidyr,pivot_wider)

R/dynamic.R

Lines changed: 38 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -15,26 +15,6 @@
1515
#
1616
# You should have received a copy of the GNU General Public License
1717
# along with this program. If not, see <http://www.gnu.org/licenses/>.
18-
#
19-
# =====================================================================
20-
21-
## Collection of functions to calculate cost-effectiveness model results
22-
## with dynamic pricing and uptake
23-
## =====================================================================
24-
25-
#' Trim the tailing zeroes from a long vector
26-
#'
27-
#' @param vec Vector. Final elements may be zero.
28-
#' @returns A vector whose length is shorter than the original, if there were trailing zero elements
29-
#' @export
30-
#' @examples
31-
#' trim_vec(c(1:10, rep(0,3)))
32-
trim_vec <- function(vec){
33-
# Identify the last element before vector elements are zero
34-
trimto <- which(rev(cumsum(rev(vec)))==vec)[1]
35-
# Return trimmed vector
36-
return(vec[1:trimto])
37-
}
3818

3919
#' Calculate present value for a payoff with dynamic pricing and dynamic uptake
4020
#'
@@ -45,21 +25,20 @@ trim_vec <- function(vec){
4525
#' @param payoffs Vector of payoffs of interest (numeric vector)
4626
#' @param prices Vector of price indices through the time horizon of interest
4727
#' @param discrate Discount rate per timestep, corresponding to price index
48-
#' @param dpv_name Name to be given to Dynamic Present Value object created by this function call
49-
#' @returns A list containing `inputs` and `results`.
50-
#' The `inputs` list contains a list of the following parameters called with the function: `uptakes, payoffs, horizon, tzero, prices`, and `discrate`.
51-
#' The `results` output is a "dynpv" object (created by [class_dynpv()]) that contains the following elements:
52-
#' - `name`: Name given to the object
53-
#' - `df`: Tibble of calculation results
54-
#' - `ncoh`: Number of cohorts of uptaking patients
55-
#' - `ntimes`: Number of times (unique values of tzero) at which calculations are performed
56-
#' - `uptake`: Total number of uptaking patients
57-
#' - `total`: Total present value
58-
#' - `mean`: Average present value per uptaking patient (=total/uptake)
59-
#' - `sum_by_coh`: Tibble of summarized calculation results for each uptake cohort
28+
#' @returns A tibble of class "dynpv" with the following columns:
29+
#' - `j`: todo
30+
#' - `k`: todo
31+
#' - `l`: todo
32+
#' - `t`: todo
33+
#' - `uj`: todo
34+
#' - `pk`: todo
35+
#' - `R`: todo
36+
#' - `v`: todo
37+
#' - `pv`: todo
6038
#' @export
61-
#' @importFrom rlang .data
6239
#' @examples
40+
#' library(dplyr)
41+
#'
6342
#' # Obtain dataset
6443
#' democe <- get_dynfields(
6544
#' heemodel = oncpsm,
@@ -69,57 +48,58 @@ trim_vec <- function(vec){
6948
#'
7049
#' # Obtain short payoff vector of interest
7150
#' payoffs <- democe |>
72-
#' dplyr::filter(int=="new", model_time<11) |>
73-
#' dplyr::mutate(cost_oth = cost_total - cost_daq_new)
51+
#' filter(int=="new", model_time<11) |>
52+
#' mutate(cost_oth = cost_total - cost_daq_new)
7453
#' Nt <- nrow(payoffs)
7554
#'
7655
#' # Example calculation
77-
#' dynpv(
56+
#' pv <- dynpv(
7857
#' uptakes = rep(1, Nt),
7958
#' payoffs = payoffs$cost_oth,
8059
#' prices = 1 + (0:(Nt-1))*0.05,
8160
#' discrate = 0.08
8261
#' )
62+
#' pv
63+
#' summary(pv)
8364
dynpv <- function(
8465
uptakes = 1,
8566
payoffs,
8667
horizon = length(payoffs),
8768
tzero = 0,
8869
prices = rep(1, length(payoffs)+tzero),
89-
discrate = 0,
90-
dpv_name = NA_character_
70+
discrate = 0
9171
){
9272
# Avoid no visible binding note
93-
j <- k <- l <- uj <- pk <- R <- v <- pv <- spv <- total <- suptakes <- NULL
73+
j <- k <- l <- uj <- pk <- R <- v <- NULL
9474
# Trim
9575
uptakes <- trim_vec(uptakes)
9676
payoffs <- trim_vec(payoffs)
9777
# Create a dataset for each combination of time
98-
df <- tidyr::expand_grid(j=1:length(uptakes), k=1:length(payoffs), l=tzero) |>
99-
dplyr::mutate(t= j + k - 1) |>
78+
df <- expand_grid(j=1:length(uptakes), k=1:length(payoffs), l=tzero) |>
79+
mutate(t= j + k - 1) |>
10080
# Remove time entries that are outside the time horizon
101-
dplyr::filter(t <= horizon) |>
102-
dplyr::mutate(
81+
filter(t <= horizon) |>
82+
mutate(
10383
uj = uptakes[j],
10484
pk = payoffs[k],
10585
R = prices[l + t],
10686
v = (1+discrate)^(1 - t),
10787
pv = uj * pk * R * v
10888
)
109-
110-
# Put dataset into a dynpv_class object
111-
cds <- class_dynpv(name = dpv_name, df = df)
112-
113-
return(list(
114-
inputs = list(
115-
uptakes = uptakes,
116-
payoffs = payoffs,
117-
horizon = horizon,
118-
tzero = tzero,
119-
prices = prices,
120-
discrate = discrate
121-
),
122-
results = cds
123-
))
89+
class(df) <- c("dynpv", class(df))
90+
return(df)
12491
}
12592

93+
#' Trim the tailing zeroes from a long vector
94+
#'
95+
#' @param vec Vector. Final elements may be zero.
96+
#' @returns A vector whose length is shorter than the original, if there were trailing zero elements
97+
#' @export
98+
#' @examples
99+
#' trim_vec(c(1:10, rep(0,3)))
100+
trim_vec <- function(vec){
101+
# Identify the last element before vector elements are zero
102+
trimto <- which(rev(cumsum(rev(vec)))==vec)[1]
103+
# Return trimmed vector
104+
return(vec[1:trimto])
105+
}

R/dynamicpv-package.R

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
#' @importFrom dplyr across all_of as_tibble bind_rows filter join_by left_join mutate rename select summarize
2+
#' @importFrom tidyr expand_grid pivot_wider
13
#' @keywords internal
24
"_PACKAGE"
35

46
## usethis namespace: start
57
## usethis namespace: end
6-
NULL
8+
NULL

R/extract.R

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515
#
1616
# You should have received a copy of the GNU General Public License
1717
# along with this program. If not, see <http://www.gnu.org/licenses/>.
18-
#
19-
# =====================================================================
2018

2119
## Collection of functions to extract payoffs from other systems, e.g. heemod
2220
## ==========================================================================
@@ -27,11 +25,10 @@
2725
#' @param discount Name of parameter providing discount rate per cycle (string)
2826
#' @param fname Export data to a .CSV file of this name, if given (character)
2927
#' @returns Tibble of payoffs taken from the heemod model, by intervention and model timestep (`model_time`).
30-
#'
28+
#'
3129
#' 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.
32-
#'
30+
#'
3331
#' 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`.
34-
#' @importFrom rlang .data
3532
#' @seealso [heemod::heemod-package]
3633
#' @export
3734
#' @examples
@@ -53,21 +50,21 @@ get_dynfields <- function(heemodel, payoffs, discount, fname=NA){
5350
# Pull in tibble into list for each intervention
5451
for (i in seq(int)){
5552
ds[[i]] <- heemodel$eval_strategy_list[[int[i]]]$values |>
56-
dplyr::as_tibble() |>
57-
dplyr::select(c("model_time", dplyr::all_of(payoffs))) |>
58-
dplyr::mutate(int = int[i])
53+
as_tibble() |>
54+
select(c("model_time", all_of(payoffs))) |>
55+
mutate(int = int[i])
5956
}
6057
# Unnest
61-
ds <- dplyr::bind_rows(ds) |>
58+
ds <- bind_rows(ds) |>
6259
# Add discounting variable
63-
dplyr::mutate(vt = (1 + discrate)^(1 - model_time))
60+
mutate(vt = (1 + discrate)^(1 - model_time))
6461
# Create rolled-up variables, with "r" prefix to their name
6562
rs <- ds |>
66-
dplyr::mutate(dplyr::across(dplyr::all_of(payoffs), ~.x/vt))
63+
mutate(across(all_of(payoffs), ~.x/vt))
6764
# Join the rolled-up data to the original data
6865
ds <- ds |>
69-
dplyr::left_join(rs, by=c("model_time", "int"), suffix=c("", "_rup")) |>
70-
dplyr::select(-vt_rup)
66+
left_join(rs, by=c("model_time", "int"), suffix=c("", "_rup")) |>
67+
select(-vt_rup)
7168
# Export as CSV
7269
if (!is.na(fname)) {readr::write_csv(ds, file=paste0(fname, ".csv"))}
7370
# Return
@@ -87,4 +84,4 @@ get_dynfields <- function(heemodel, payoffs, discount, fname=NA){
8784
#' )
8885
get_param_value <- function(heemodel, param){
8986
rlang::eval_tidy(heemodel$parameters[[param]])
90-
}
87+
}

R/future.R

Lines changed: 12 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -15,71 +15,52 @@
1515
#
1616
# You should have received a copy of the GNU General Public License
1717
# along with this program. If not, see <http://www.gnu.org/licenses/>.
18-
#
19-
# =====================================================================
2018

2119
## Convenience function to calculate 'future' cost-effectiveness results
2220
## ========================================================================
2321

2422
#' Calculate present value for a payoff in a single cohort with dynamic pricing across multiple timepoints
25-
#'
23+
#'
2624
#' 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.
27-
#' @inheritParams dynpv
2825
#' @seealso [dynpv()]
29-
#' @returns A list `inputs`, `results` and `pv`.
30-
#' The `inputs` list contains a list of the following parameters called with the function: `uptakes, payoffs, horizon, tzero, prices`, and `discrate`.
31-
#' The `results` output is a "dynpv" object (created by [class_dynpv()]) that contains the following elements:
32-
#' - `name`: Name given to the object
33-
#' - `df`: Tibble of calculation results
34-
#' - `ncoh`: Number of cohorts of uptaking patients (always 1)
35-
#' - `ntimes`: Number of times (unique values of tzero) at which calculations are performed
36-
#' - `uptake`: Total number of uptaking patients (always 1)
37-
#' - `total`: Total present value
38-
#' - `mean`: Average present value per uptaking patient (=total/uptake)
39-
#' - `sum_by_coh`: Tibble of summarized calculation results for each uptake cohort
40-
#' - `inputs`: list contains a list of the following parameters called with the function: `uptakes, payoffs, horizon, tzero, prices`, and `discrate`.
41-
#' The `pv` output is numeric, a convenience value equal to `$results$mean`.
26+
#' @inherit dynpv params return
4227
#' @export
4328
#' @examples
29+
#' library(dplyr)
30+
#'
4431
#' # Obtain dataset
4532
#' democe <- get_dynfields(
4633
#' heemodel = oncpsm,
4734
#' payoffs = c("cost_daq_new", "cost_total", "qaly"),
4835
#' discount = "disc"
4936
#' )
50-
#'
37+
#'
5138
#' # Obtain discount rate
5239
#' discrate <- get_param_value(oncpsm, "disc")
53-
#'
40+
#'
5441
#' # Obtain payoff vector of interest
5542
#' payoffs <- democe |>
56-
#' dplyr::filter(int=="new") |>
57-
#' dplyr::mutate(cost_oth_rup = cost_total_rup - cost_daq_new_rup)
43+
#' filter(int=="new") |>
44+
#' mutate(cost_oth_rup = cost_total_rup - cost_daq_new_rup)
5845
#' Nt <- nrow(payoffs)
59-
#'
46+
#'
6047
#' # Run calculation for times 0-9
6148
#' fpv <- futurepv(
6249
#' tzero = (0:9)*52,
6350
#' payoffs = payoffs$cost_oth_rup,
6451
#' prices = 1.001^(1:(2*Nt)-1), # Approx 5.3% every 52 steps
6552
#' discrate = 0.001 + discrate
6653
#' )
67-
#' fpv$results
68-
#' fpv$pv
54+
#' fpv
55+
#' summary(fpv)
6956
futurepv <- function(tzero=0, payoffs, prices, discrate){
7057
# Wrapper for dynpv with uptakes=1 and horizon=length(payoffs)
71-
dpv <- dynpv(
58+
dynpv(
7259
uptakes = 1,
7360
payoffs = payoffs,
7461
horizon = length(payoffs),
7562
tzero = tzero,
7663
prices = prices,
7764
discrate = discrate
7865
)
79-
# Only return useful outputs
80-
list(
81-
inputs = dpv$inputs,
82-
results = dpv$results,
83-
pv = dpv$results$mean
84-
)
8566
}

0 commit comments

Comments
 (0)