数据资源下载地址:https://download.csdn.net/download/weixin_68126662/89101333

久菜盒子|可实现需求|Advanced Economic Evaluation(作业,资源免费获取)-LMLPHP

久菜盒子|可实现需求|Advanced Economic Evaluation(作业,资源免费获取)-LMLPHP

久菜盒子|可实现需求|Advanced Economic Evaluation(作业,资源免费获取)-LMLPHP

 久菜盒子|可实现需求|Advanced Economic Evaluation(作业,资源免费获取)-LMLPHP

 久菜盒子|可实现需求|Advanced Economic Evaluation(作业,资源免费获取)-LMLPHP

 R代码参考:

#############################################################################
### 
### GLBH0046: Advanced Economic Evaluation
###
### Practical 1: Resource use and costs
###
#############################################################################

rm(list=ls())

# Set working directory and load the dataset
setwd("N:/Manuel Gomes/Teaching/Advanced EE/Practicals/Practicals 1-2")

# Load the data (using the 'haven' library, which reads Stata data files directly)
library(haven)
data<- read_dta('evar.dta')

# Familiarise with dataset
names(data)   # variable names
print(data)   # visualise data (first 10 rows)
summary(data) # basic descritptive stats for all the variables


### Question 3
#define unit costs 
device_evar <- 5500
device_or <- 700
drug_evar <- 600
drug_or <- 400
oheads <- 2
staff_evar <- 12
staff_or <- 9
cc <- 1400
gm <- 260
out <- 140
gp <- 60
nurse <- 20
icare <- 160
prod <- 65

# Consumables - assign medical device and drug costs to individuals by arm
device_cost <- ifelse(data$arm==1, device_evar, device_or)
drug_cost <- ifelse(data$arm==1, drug_evar, drug_or)
data$cons_cost <- device_cost + drug_cost

# Theatre costs - combine time (in min) spent in theatre with unit costs
overhead_cost <- data$theatre_los*oheads 
staff_cost <- ifelse(data$arm==1, data$theatre_los*staff_evar, data$theatre_los*staff_or)
data$theatre_cost <- overhead_cost + staff_cost

# Critical care cost - combine bed-days spent in critical care with unit cost
data$cc_cost <-data$cc_los*cc

# General medical ward cost - combine bed-days spent in general medical ward with unit cost
data$gm_cost <-data$gm_los*gm

# Outpatient cost - combine outpatient visits with unit cost
data$out_cost <-data$out_los*out

# GP cost - combine GP and nurse visits with unit cost
gp_cost <- data$gp_visit*gp
nurse_cost <- data$nurse_visit*nurse
data$primary_cost <- gp_cost + nurse_cost

# Summarise costs across components using with either 'tapply' or 'aggregate' functions

#tapply(data$theatre_cost, data$arm, function(x) c(mean(x), sd(x)))
tc<-with(data, aggregate(data$theatre_cost ~ data$arm, FUN=function(x) c(mean=mean(x),SD=sd(x) )))
cc<-with(data, aggregate(data$cc_cost ~ data$arm, FUN=function(x) c(mean=mean(x),SD=sd(x) )))
gc<-with(data, aggregate(data$gm_cost ~ data$arm, FUN=function(x) c(mean=mean(x),SD=sd(x) )))
oc<-with(data, aggregate(data$out_cost ~ data$arm, FUN=function(x) c(mean=mean(x),SD=sd(x) )))
pc<-with(data, aggregate(data$primary_cost ~ data$arm, FUN=function(x) c(mean=mean(x),SD=sd(x) )))

#you may wish to combine results in a table
table <- rbind(t(tc), t(cc)[2:3,], t(gc)[2:3,], t(oc)[2:3,], t(pc)[2:3,])
table

# More compact using 'dplyr' library (advanced)
library(dplyr)
data %>%
  group_by(arm) %>% 
  summarise(across(
      .cols = theatre_cost:primary_cost, 
      .fns = list(Mean = mean, SD = sd), na.rm = TRUE, 
      .names = "{col}_{fn}"
  ))


### Question 5
# Calculate total cost
data$total_cost <- data$cons_cost + data$theatre_cost + data$cc_cost + 
                   data$gm_cost + data$out_cost + data$primary_cost
     
# Report mean difference (and 95% CI) in total cost for EVAR and Open Repair
tapply(data$total_cost, data$arm, function(x) c(mean(x), sd(x)))
lm(data$total_cost ~ data$arm) 

t.test(data$total_cost ~ data$arm, conf.level = 0.95) 


### Question 6
# Informal care cost - combine number days of informal care with unit cost
data$inf_cost <-data$carer*icare

# Productivity losses - combine number days off work with unit cost
data$work_cost <-data$off_work*prod

# Calculate total cost under societal perspective
data$total_cost_soc <- data$total_cost + data$inf_cost + data$work_cost

# Report mean difference (and 95% CI) in total cost for EVAR and Open Repair
tapply(data$total_cost_soc, data$arm, function(x) c(mean(x), sd(x)))
lm(data$total_cost_soc ~ data$arm) 

t.test(data$total_cost_soc ~ data$arm, conf.level = 0.95) 


### Question 7

# plot distribution (histogram) of total healthcare costs by trial arm
library(ggplot2)
ggplot(data, aes(x = total_cost)) +
  geom_histogram(fill = "white", colour = "black") +
  facet_grid(data$arm ~ .)

# Alternative forms to address the skewness

# Parametric
# GLM, considering a distribution that better fits the skewed costs (e.g. Gamma)
gamma.mod<-glm(data$total_cost ~ data$arm, family=Gamma(link="identity")) 
cbind(coef(gamma.mod), confint(gamma.mod)) 

qqnorm(residuals(gamma.mod), main="")
qqline(residuals(gamma.mod))


# Non-parametric
# Non-parametric bootstrap using 'boot' package
library(boot)  

# create function that estimates parameter of interest
inc.cost <- function(data, indices) {
  d <- data[indices,] # allows boot to sample from the original data
  lm <- lm(total_cost ~ arm, data=d) 
  inc.cost<-coef(lm)[2]
  return(inc.cost)
}

# run R=1000 bootstrap replications
set.seed(90210) # set seed to ensure same results after re-runs
b <- boot(data=data, statistic=inc.cost, R=1000)
plot(b)
mean(b$t) # incremental cost is just the average of the Bootstrap replicates

# Report 95% CI using 'boot.ci'
# It takes the 2.5% and 97.5% percentiles of the distribution of Bootstrap replicates
# Here we consider bias-corrected and accelerated (BCa) percentiles (more appropriate for skewed data)
boot.ci(b, type="bca")


# save the dataset (cost data will be needed for next practical)
write_dta(data,'costs.dta')


#############################################################################
### 
### GLBH0046: Advanced Economic Evaluation
###
### Practical 2: QALYs
###
#############################################################################

rm(list=ls())

# Set working directory and load the dataset
setwd("N:/Manuel Gomes/Teaching/Advanced EE/Practicals/Practicals 1-2")

# Load the data (using the 'haven' library, which reads Stata data files directly)
library(haven)
data<- read_dta('evar.dta')


### QUESTION 2
library(eq5d)
library(ggplot2)

#Estimate eq5d score at 1 month   
data$eq5d_1mo <- eq5d(scores= data.frame(
                      MO=c(data$q1_1mo),
                      SC=c(data$q2_1mo),
                      UA=c(data$q3_1mo),
                      PD=c(data$q4_1mo),
                      AD=c(data$q5_1mo)),
                    country="UK", version="3L", type="TTO", ignore.invalid=TRUE) #ignore NAs
  
  ggplot(data, aes(x = eq5d_1mo)) +      # histogram of EQ-5D score at 1 month
  geom_histogram(fill = "white", colour = "black") +
  facet_grid(arm ~ .)

#Estimate eq5d score at 3 months   
data$eq5d_3mo <- eq5d(scores= data.frame(
                      MO=c(data$q1_3mo),
                      SC=c(data$q2_3mo),
                      UA=c(data$q3_3mo),
                      PD=c(data$q4_3mo),
                      AD=c(data$q5_3mo)),
                    country="UK", version="3L", type="TTO", ignore.invalid=TRUE) #ignore NAs

#Estimate eq5d score at 12 months   
data$eq5d_12mo <- eq5d(scores= data.frame(
                      MO=c(data$q1_12mo),
                      SC=c(data$q2_12mo),
                      UA=c(data$q3_12mo),
                      PD=c(data$q4_12mo),
                      AD=c(data$q5_12mo)),
                    country="UK", version="3L", type="TTO", ignore.invalid=TRUE) #ignore NAs


### QUESTION 3
# Summarise EQ-5D-3L for survivors (i.e. ignore NAs for deceased patients)
# 1 month
tapply(data$eq5d_1mo[data$death30days==0], data$arm[data$death30days==0], function(x) c(mean(x), sd(x)))
lm1<-lm(data$eq5d_1mo ~ data$arm) 
cbind(coef(lm1), confint(lm1)) 

# 3 months
tapply(data$eq5d_3mo[data$death3mnth==0], data$arm[data$death3mnth==0], function(x) c(mean(x), sd(x)))
lm3<-lm(data$eq5d_3mo ~ data$arm) 
cbind(coef(lm3), confint(lm3)) 

# 12 months
tapply(data$eq5d_12mo[data$death1year==0], data$arm[data$death1year==0], function(x) c(mean(x), sd(x)))
lm12<-lm(data$eq5d_12mo ~ data$arm)
cbind(coef(lm12), confint(lm12)) 


### QUESTION 4
# 1 month
# Report number of deceased per treatment arm 
tapply(data$death30days, data$arm, function(x) c(sum(x), sum(x)/length(x)))
# run logistic regression and report odds-ratio (exponentiate results)
logist1 <- glm(data$death30days ~ data$arm, data = data, family = "binomial"(link="logit"))
exp(cbind(coef(logist1), confint(logist1))) 

# 3 months
tapply(data$death3mnth, data$arm, function(x) c(sum(x), sum(x)/length(x)))
logist3 <- glm(data$death3mnth ~ data$arm, data = data, family = "binomial"(link="logit"))
exp(cbind(coef(logist3), confint(logist3))) 

# 12 months
tapply(data$death1year, data$arm, function(x) c(sum(x), sum(x)/length(x)))
logist12 <- glm(data$death1year ~ data$arm, data = data, family = "binomial"(link="logit"))
exp(cbind(coef(logist12), confint(logist12))) 

# Plot survival (Kaplan-Meier) curves
library(survival)
library(survminer)
data$ttd[data$ttd>365]<-365.25 # focus on time till death or censoring (ttd) within 12 months
kmfit <- survfit( Surv(data$ttd, data$death1year==1) ~ data$arm)

# plot survival curves using 'ggsurvplot'
ggsurvplot(
  kmfit,                   # survfit object with calculated KM statistics
  data = data,           
  risk.table = TRUE,       # show no. patients at risk
  pval = TRUE,             # show p-value of log-rank test.
  conf.int = TRUE,         # show confidence intervals for point estimates of survival curves.
  xlim = c(0,366),        # edit X axis
)


### QUESTION 5
# Calculate QALYs for individuals who survive up to 12 months (assuming eq-5d is zero at baseline)
data$qaly <- 0.125*data$eq5d_1mo + (5.5/12)*data$eq5d_3mo + 0.375*data$eq5d_12mo

# Replace QALYs=0 for individuals who die between baseline and 1st month
data$qaly[data$death30days==1] <- 0

# Calculate QALYs for individuals who die between 1 and 3 months
data$qaly[data$death30days==0 & data$death3mnth==1] <- (data$ttd[data$death30days==0 & data$death3mnth==1]/365)*0.5*data$eq5d_1mo[data$death30days==0 & data$death3mnth==1]

# Calculate QALYs for individuals who die between 3 and 12 months
data$qaly[data$death3mnth==0 & data$death1year==1] <- 0.125*data$eq5d_1mo[data$death3mnth==0 & data$death1year==1] +
  (data$ttd[data$death3mnth==0 & data$death1year==1]/365-(1/12))*0.5*data$eq5d_3mo[data$death3mnth==0 & data$death1year==1]

# Plot QALYs
ggplot(data, aes(x = qaly)) +
  geom_histogram(fill = "white", colour = "black") +
  facet_grid(arm ~ .)


### QUESTION 6
# Incremental QALY at 12 months
tapply(data$qaly, data$arm, function(x) c(mean(x), sd(x)))

# estimate 95% CI via Bootstrap
library(boot)  
inc.qaly <- function(data, indices) {
  d <- data[indices,] # allows boot to sample from the original data
  lm <- lm(qaly ~ arm, data=d) 
  inc.qaly<-coef(lm)[2]
  return(inc.qaly)
}
set.seed(90210) # set seed to ensure same results after re-runs
b <- boot(data=data, statistic=inc.qaly, R=1000)
mean(b$t) # incremental qaly
boot.ci(b, type="bca")

### QUESTION 7
# Cost-effectiveness at 12 months

# add total cost variable to main dataset (make sure both datasets are sorted by 'patientid')
data.cost<-read_dta('costs.dta')
data$total_cost<-data.cost$total_cost

# create function that extracts both incremental cost and QALY
cea <- function(data, indices) {
  d <- data[indices,] # allows boot to sample from the original data
  inc.cost<-coef(lm(total_cost ~ arm, data=d))[2]
  inc.qaly<-coef(lm(qaly ~ arm, data=d))[2]
  return(c(inc.qaly,inc.cost))
}

# run bootstrap
set.seed(90210) # set seed to ensure same results after re-runs
b <- boot(data=data, statistic=cea, R=1000)

mean(b$t[,2])/mean(b$t[,1])         # ICER
mean(b$t[,1]*30000-b$t[,2])         # INB (assuming a threshold of ?30,000 per QALY)
boot.cea<-cbind(b$t[,1], b$t[,2])   # bootstrap sample of incremental QALY and cost

# cost-effectiveness plane
par(las=1)
plot(boot.cea,  main=" ", xlab="", ylab="", 
     xlim=c(-.1,.2), ylim=c(-6000,6000),pch=19, cex=0.7, col="darkslategray", axes=F )
points(x=mean(b$t[,1]), y=mean(b$t[,2]), col='red', cex=1, pch=16)
axis(1, pos=0, cex.axis=1)
axis(2, pos=0, cex.axis=1)
abline(0,30000, lty='dotted')
text(0.15, 3500, "WTP ?30,000", cex=1)
mtext(side=1, "Incremental QALY", cex=1)
mtext(side=2, "Incremental cost", cex=1, las=0)


#############################################################################
### 
### GLBH0046: Advanced Economic Evaluation
###
### Practical 3: Markov model set-up
###
#############################################################################

rm(list=ls())

# Set working directory and load the dataset
setwd("N:/Manuel Gomes/Teaching/Advanced EE/Practicals/Practicals 4-7")


### QUESTION 6

### 6.1 - create vectors for key inputs

# treatments
treat <- c("EVAR", "OR")    # treatments
n_treat <- length(treat)    # no. treatments

# health states (E: event-free survival, C: CVD event, D: Death)
states <- c("E", "C", "D")
n_states <- length(states)  # no. states

# cohort
n <- "size"              # size of the cohort

# cycles
n_cycles <- 10           # no. cycles (*to be modified)


### 6.2 costs for each health state

c_E <- "cost_E"         # cost in E state
c_C <- "cost_C"         # cost in C state
c_D <- "cost_D"         # cost in D state
c_evar <- "cost_evar"   # Cost of EVAR treatment (one-off)
c_or <- "cost_or"       # Cost of Open Repair treatment (one-off)


### 6.2.1 costs matrix across states and treatment groups

c_matrix <- matrix(
            c(c_E, c_C, c_D,   
              c_E, c_C, c_D),
         byrow = TRUE,
         nrow = n_treat,
         dimnames = list(treat,states))


### 6.3 utilities for each health state

u_E <- "utility_E"         # utility in E state
u_C <- "utility_C"         # utility in C state
u_D <- "utility_D"         # utility in D state

### 6.3.1 utilities matrix across states and treatment groups

u_matrix <- matrix(
  c(u_E, u_C, u_D,   
    u_E, u_C, u_D),
  byrow = TRUE,
  nrow = n_treat,
  dimnames = list(treat,states))


### 6.4 transition probabilities between health states 

p_EC <- "prob_EC"         # transition probability from E to C state
p_CE <- "prob_CE"         # transition probability from C to E state
p_ED <- "prob_ED"         # transition probability from E to D state
p_CD <- "prob_CD"         # transition probability from C to D state

effect<- "treat_effect"      # effect of treatment (reduces progression)


# 6.4.1 create matrix with all transition rates per treatment arm

# initialise transition matrix
p_mat <- array(data = NA,
                  dim = c(n_states, n_states, n_treat),
                  dimnames = list(from = states,
                                  to = states,
                                  treat))

# Fill in the matrix (Open Repair)
# From E
p_mat["E", "E", "OR"] <- "1 - p_EC - p_ED"
p_mat["E", "C", "OR"] <- "p_EC"
p_mat["E", "D", "OR"] <- "p_ED"
# From C
p_mat["C", "E", "OR"] <- "p_CE"
p_mat["C", "C", "OR"] <- "1 - p_CD - p_CE"
p_mat["C", "D", "OR"] <- "p_CD"
# From D
p_mat["D", "E", "OR"] <- 0
p_mat["D", "C", "OR"] <- 0
p_mat["D", "D", "OR"] <- 1

# Fill in the matrix (EVAR)
# From E
p_mat["E", "E", "EVAR"] <- "1 - p_EC*(1-effect) - p_ED"
p_mat["E", "C", "EVAR"] <- "p_EC*(1-effect)"
p_mat["E", "D", "EVAR"] <- "p_ED"
# From C
p_mat["C", "E", "EVAR"] <- "p_CE"
p_mat["C", "C", "EVAR"] <- "1 - p_CD - p_CE"
p_mat["C", "D", "EVAR"] <- "p_CD"
# From D
p_mat["D", "E", "EVAR"] <- 0
p_mat["D", "C", "EVAR"] <- 0
p_mat["D", "D", "EVAR"] <- 1


### 6.5 Create empty arrays to store model output

# Matrix to store numbers of individuals in each health state across cycles
pop <- array(data = NA,
             dim = c(n_states, n_cycles+1, n_treat),
             dimnames = list(state = states,
                             cycle = NULL,
                             treatment = treat))
# first cycle
pop["E", cycle = 1, ] <- n
pop["C", cycle = 1, ] <- 0
pop["D", cycle = 1, ] <- 0


# Matrix to store cost-effectiveness endpoints
costs <- LYs <- QALYs <- array(data = NA,
                         dim = c(n_treat, n_cycles+1),
                         dimnames = list(treatment = treat,
                             cycle = NULL))

# vector to store total life years (LYs), QALYs and costs
total_LYs <- total_QALYs <- total_costs <- setNames(c(NA, NA), treat)


### 6.6 set up loops to run the model

# outer loop - loop over treatment groups
for (i in 1:n_treat) {      
  
# inner loop - loop over cycles 
  for (j in 2:n_cycles) {       # starts in cycle 2 as cycle 1 is already defined above
    
    pop[, cycle = j, treatment = i] <-
      pop[, cycle = j - 1, treatment = i]  %*% p_mat[, , treatment = i]
    
  }
}  


#############################################################################
### 
### GLBH0046: Advanced Economic Evaluation
###
### Practical 4: Populate Markov model
###
#############################################################################

rm(list=ls())

# Set working directory and load the dataset
setwd("N:/Manuel Gomes/Teaching/Advanced EE/Practicals/Practicals 4-7")


### QUESTION 5

# Populate Markov model

# treatments
treat <- c("EVAR", "OR")    # treatments
n_treat <- length(treat)    # no. treatments

# health states (E: event-free survival, C: CVD event, D: Death)
states <- c("E", "C", "D")
n_states <- length(states)  # no. states

# cohort
n <- 1000                # size of the cohort
age0 <- 55               # initial age of cohort

# cycles
n_cycles <- 43           # no. cycles

# Discount rate (same for costs and QALYs)
dr <- 0.035

# costs for each health state

c_E <- 500          # cost in E state
c_C <- 2500         # cost in C state
c_D <- 0            # cost in D state
c_evar <- 18000     # Cost of EVAR treatment (one-off)
c_or <- 15500       # Cost of Open Repair treatment (one-off)


# costs matrix across states and treatment groups

c_matrix <- matrix(
            c(c_E, c_C, c_D, 
              c_E, c_C, c_D),
         byrow = TRUE,
         nrow = n_treat,
         dimnames = list(treat,states))


# utilities for each health state

u_E <- 0.80         # utility in E state
u_C <- 0.60         # utility in C state
u_D <- 0            # utility in D state

# utilities matrix across states and treatment groups

u_matrix <- matrix(
  c(u_E, u_C, u_D,   
    u_E, u_C, u_D),
  byrow = TRUE,
  nrow = n_treat,
  dimnames = list(treat,states))


# annual transition probabilities between health states 

p_EC <- 0.05         # transition probability from E to C state
p_CE <- 0.22         # transition probability from C to E state
p_ED <- 0.04         # transition probability from E to D state
p_CD <- 0.14         # transition probability from C to D state

effect<- 0.1         # effect of treatment (reduces progression)


# 6.4.1 create matrix with all transition rates per treatment arm

# initialise transition matrix
p_mat <- array(data = NA,
                  dim = c(n_states, n_states, n_treat),
                  dimnames = list(from = states,
                                  to = states,
                                  treat))

# Fill in the matrix (Open Repair)
# From E
p_mat["E", "E", "OR"] <- 1 - p_EC - p_ED
p_mat["E", "C", "OR"] <- p_EC
p_mat["E", "D", "OR"] <- p_ED
# From C
p_mat["C", "E", "OR"] <- p_CE
p_mat["C", "C", "OR"] <- 1 - p_CD - p_CE
p_mat["C", "D", "OR"] <- p_CD
# From D
p_mat["D", "E", "OR"] <- 0
p_mat["D", "C", "OR"] <- 0
p_mat["D", "D", "OR"] <- 1

# Fill in the matrix (EVAR)
# From E
p_mat["E", "E", "EVAR"] <- 1 - p_EC*(1-effect) - p_ED
p_mat["E", "C", "EVAR"] <- p_EC*(1-effect)
p_mat["E", "D", "EVAR"] <- p_ED
# From C
p_mat["C", "E", "EVAR"] <- p_CE
p_mat["C", "C", "EVAR"] <- 1 - p_CD - p_CE
p_mat["C", "D", "EVAR"] <- p_CD
# From D
p_mat["D", "E", "EVAR"] <- 0
p_mat["D", "C", "EVAR"] <- 0
p_mat["D", "D", "EVAR"] <- 1


# Create empty matrices to store model output

# Matrix to store numbers of individuals in each health state across cycles
pop <- array(data = NA,
             dim = c(n_states, n_cycles+1, n_treat),   
             dimnames = list(state = states,
                             cycle = NULL,
                             treatment = treat))

# first cycle
pop["E", cycle = 1, ] <- n
pop["C", cycle = 1, ] <- 0
pop["D", cycle = 1, ] <- 0


# Matrix to store cost-effectiveness endpoints
costs <- LYs <- QALYs  <- array(data = NA,
                        dim = c(n_treat, n_cycles+1),
                        dimnames = list(treatment = treat,
                             cycle = NULL))

# vector to store total life years (LYs), QALYs and costs
total_LYs <- total_QALYs <- total_costs <- setNames(c(NA, NA), treat)


### Run the model

# outer loop - loop over treatment groups
for (i in 1:n_treat) {      
  
# inner loop - loop over cycles 
  for (j in 1:n_cycles) {       
    
    pop[, cycle = j+1, treatment = i] <-     # starts in cycle 2 as cycle 1 is already defined above
      pop[, cycle = j, treatment = i] %*% p_mat[, , treatment = i]

  } # end of inner loop

# Life-years - 1 if person alive (i.e states E and C), 0 otherwise (state D)
LYs[i, ] <- (c(1,1,0) %*% pop[, , treatment = i]) * 1/(1 + dr)^(0:n_cycles)   # cycle 1 = Year 0

# Quality-adjusted life-years (LYs adjusted by the quality of life)
QALYs[i, ] <- (u_matrix[treatment = i, ] %*% pop[, , treatment = i]) * 1/(1 + dr)^(0:n_cycles)

# Costs
costs[i, ] <-(c_matrix[treatment = i, ] %*% pop[, , treatment = i]) * 1/(1 + dr)^(0:n_cycles)

total_LYs[i] <- sum(LYs[treatment = i, -1])       # -1 means 'exclude Year 0'
total_QALYs[i] <- sum(QALYs[treatment = i, -1])
total_costs[i] <- sum(costs[treatment = i, -1])

}  # end of outer loop

# Add one-off cost (per patient) of the intervention
total_costs<-c(total_costs["EVAR"] + c_evar*n, total_costs["OR"] + c_or*n)


### Question 6

# incremental LY
inc_ly <- total_LYs["EVAR"] - total_LYs["OR"]

# incremental QALY
inc_qaly <- total_QALYs["EVAR"] - total_QALYs["OR"]

# Incremental costs 
inc_cost <- total_costs["EVAR"] - total_costs["OR"]

# Incremental net benefit, assuming a WTP threshold of �30,000 per QALY4
inb<-inc_qaly*30000-inc_cost

# Incremental cost-effectiveness ratio
icer <- inc_cost/inc_qaly

total_LYs
total_QALYs
total_costs
inc_ly
inc_qaly
inc_cost
inb
Icer


#############################################################################
### 
### GLBH0046: Advanced Economic Evaluation
###
### Practical 5: Deterministic sensitivity analysis
###
#############################################################################


#############################################################################
#
### Question 4
#
#############################################################################


rm(list=ls())

# Set working directory and load the dataset
setwd("N:/Manuel Gomes/Teaching/Advanced EE/Practicals/Practicals 3-6")


# Re-run Markov model with age0=75 and n_cycles=23

# treatments
treat <- c("EVAR", "OR")    # treatments
n_treat <- length(treat)    # no. treatments

# health states (E: event-free survival, C: CVD event, D: Death)
states <- c("E", "C", "D")
n_states <- length(states)  # no. states

# cohort
n <- 1000                # size of the cohort
age0 <- 75               # initial age of cohort

# cycles
n_cycles <- 23           # no. cycles

# Discount rate (same for costs and QALYs)
dr <- 0.035

# costs for each health state

c_E <- 500          # cost in E state
c_C <- 2500         # cost in C state
c_D <- 0            # cost in D state
c_evar <- 18000     # Cost of EVAR treatment (one-off)
c_or <- 15500       # Cost of Open Repair treatment (one-off)


# costs matrix across states and treatment groups

c_matrix <- matrix(
            c(c_E, c_C, c_D, 
              c_E, c_C, c_D),
         byrow = TRUE,
         nrow = n_treat,
         dimnames = list(treat,states))


# utilities for each health state

u_E <- 0.80         # utility in E state
u_C <- 0.60         # utility in C state
u_D <- 0            # utility in D state

# utilities matrix across states and treatment groups

u_matrix <- matrix(
  c(u_E, u_C, u_D,   
    u_E, u_C, u_D),
  byrow = TRUE,
  nrow = n_treat,
  dimnames = list(treat,states))


# annual transition probabilities between health states 

p_EC <- 0.05         # transition probability from E to C state
p_CE <- 0.22         # transition probability from C to E state
p_ED <- 0.04         # transition probability from E to D state
p_CD <- 0.14         # transition probability from C to D state

effect<- 0.1         # effect of treatment (reduces progression)


# 6.4.1 create matrix with all transition rates per treatment arm

# initialise transition matrix
p_mat <- array(data = NA,
                  dim = c(n_states, n_states, n_treat),
                  dimnames = list(from = states,
                                  to = states,
                                  treat))

# Fill in the matrix (Open Repair)
# From E
p_mat["E", "E", "OR"] <- 1 - p_EC - p_ED
p_mat["E", "C", "OR"] <- p_EC
p_mat["E", "D", "OR"] <- p_ED
# From C
p_mat["C", "E", "OR"] <- p_CE
p_mat["C", "C", "OR"] <- 1 - p_CD - p_CE
p_mat["C", "D", "OR"] <- p_CD
# From D
p_mat["D", "E", "OR"] <- 0
p_mat["D", "C", "OR"] <- 0
p_mat["D", "D", "OR"] <- 1

# Fill in the matrix (EVAR)
# From E
p_mat["E", "E", "EVAR"] <- 1 - p_EC*(1-effect) - p_ED
p_mat["E", "C", "EVAR"] <- p_EC*(1-effect)
p_mat["E", "D", "EVAR"] <- p_ED
# From C
p_mat["C", "E", "EVAR"] <- p_CE
p_mat["C", "C", "EVAR"] <- 1 - p_CD - p_CE
p_mat["C", "D", "EVAR"] <- p_CD
# From D
p_mat["D", "E", "EVAR"] <- 0
p_mat["D", "C", "EVAR"] <- 0
p_mat["D", "D", "EVAR"] <- 1


# Create empty matrices to store model output

# Matrix to store numbers of individuals in each health state across cycles
pop <- array(data = NA,
             dim = c(n_states, n_cycles+1, n_treat),   
             dimnames = list(state = states,
                             cycle = NULL,
                             treatment = treat))

# first cycle
pop["E", cycle = 1, ] <- n
pop["C", cycle = 1, ] <- 0
pop["D", cycle = 1, ] <- 0


# Matrix to store cost-effectiveness endpoints
costs <- LYs <- QALYs  <- array(data = NA,
                        dim = c(n_treat, n_cycles+1),
                        dimnames = list(treatment = treat,
                             cycle = NULL))

# vector to store total life years (LYs), QALYs and costs
total_LYs <- total_QALYs <- total_costs <- setNames(c(NA, NA), treat)


### Run the model

# outer loop - loop over treatment groups
for (i in 1:n_treat) {      
  
# inner loop - loop over cycles 
  for (j in 1:n_cycles) {       
    
    pop[, cycle = j+1, treatment = i] <-     # starts in cycle 2 as cycle 1 is already defined above
      pop[, cycle = j, treatment = i] %*% p_mat[, , treatment = i]

  } # end of inner loop

# Life-years - 1 if person alive (i.e states E and C), 0 otherwise (state D)
LYs[i, ] <- (c(1,1,0) %*% pop[, , treatment = i]) * 1/(1 + dr)^(0:n_cycles)   # cycle 1 = Year 0

# Quality-adjusted life-years (LYs adjusted by the quality of life)
QALYs[i, ] <- (u_matrix[treatment = i, ] %*% pop[, , treatment = i]) * 1/(1 + dr)^(0:n_cycles)

# Costs
costs[i, ] <-(c_matrix[treatment = i, ] %*% pop[, , treatment = i]) * 1/(1 + dr)^(0:n_cycles)

total_LYs[i] <- sum(LYs[treatment = i, -1])       # -1 means 'exclude Year 0'
total_QALYs[i] <- sum(QALYs[treatment = i, -1])
total_costs[i] <- sum(costs[treatment = i, -1])

}  # end of outer loop

# Add one-off cost (per patient) of the intervention
total_costs<-c(total_costs["EVAR"] + c_evar*n, total_costs["OR"] + c_or*n)

# incremental LY
inc_ly <- total_LYs["EVAR"] - total_LYs["OR"]

# incremental QALY
inc_qaly <- total_QALYs["EVAR"] - total_QALYs["OR"]

# Incremental costs 
inc_cost <- total_costs["EVAR"] - total_costs["OR"]

# Incremental net benefit at �30,000/QALY threshold
inb <- inc_qaly*30000-inc_cost

# Incremental cost-effectiveness ratio
icer <- inc_cost/inc_qaly


total_LYs
total_QALYs
total_costs
inc_ly
inc_qaly
inc_cost
inb
icer



#############################################################################
#
### Question 5
#
#############################################################################

rm(list=ls())

# Set working directory and load the dataset
setwd("N:/Manuel Gomes/Teaching/Advanced EE/Practicals/Practicals 3-6")


#############################################################################
### Step 1: initialise model set-up as before until transitions matrix

# Time-dependent transition probabilities

# treatments
treat <- c("EVAR", "OR")    # treatments
n_treat <- length(treat)    # no. treatments

# health states (E: event-free survival, C: CVD event, D: Death)
states <- c("E", "C", "D")
n_states <- length(states)  # no. states

# cohort
n <- 1000                # size of the cohort
age0 <- 55               # initial age of cohort

# cycles
n_cycles <- 43           # no. cycles

# Discount rate (same for costs and QALYs)
dr <- 0.035

# costs for each health state

c_E <- 500          # cost in E state
c_C <- 2500         # cost in C state
c_D <- 0            # cost in D state
c_evar <- 18000     # Cost of EVAR treatment (one-off)
c_or <- 15500       # Cost of Open Repair treatment (one-off)


# costs matrix across states and treatment groups

c_matrix <- matrix(
  c(c_E, c_C, c_D, 
    c_E, c_C, c_D),
  byrow = TRUE,
  nrow = n_treat,
  dimnames = list(treat,states))


# utilities for each health state

u_E <- 0.80         # utility in E state
u_C <- 0.60         # utility in C state
u_D <- 0            # utility in D state

# utilities matrix across states and treatment groups

u_matrix <- matrix(
  c(u_E, u_C, u_D,   
    u_E, u_C, u_D),
  byrow = TRUE,
  nrow = n_treat,
  dimnames = list(treat,states))


#############################################################################
### Step 2: Write function to create transition probabilities that change with age cohort

# initialise matrix as before
p_mat <- array(data = NA,
               dim = c(n_states, n_states, n_treat),
               dimnames = list(from = states,
                               to = states,
                               treat))

# Create 'lookup' function to return a matrix that includes age-related transition probabilities

p_mat_cycle <- function(p_mat, age, cycle,
                        p_EC = 0.05,
                        p_CE = 0.22,
                        excess=0.10,    # CHD-related excess mortality
                        effect = 0.1) {
  
  # p_ED will vary according to age cohort 55-64, 65-74, 75-84, 85+
  
  p_ED_lookup <-
    c("(54,64]" = 0.008,    # round bracket means 'exclusive'; square bracket means 'inclusive'
      "(64,74]" = 0.019,
      "(74,84]" = 0.056,
      "(84,98]" = 0.203)
  
  # in each cycle, p_ED value will be picked according to age cohort
  age_group <- cut(age, breaks = c(54,64,74,84,98))
  
  p_ED <- p_ED_lookup[age_group]
  p_CD <- p_ED + excess
  
  
  # Fill in the matrix (Open Repair)
  # p_EC and p_CE will be constant across cycles
  
  # From E
  p_mat["E", "E", "OR"] <- 1 - p_EC - p_ED
  p_mat["E", "C", "OR"] <- p_EC
  p_mat["E", "D", "OR"] <- p_ED
  # From C
  p_mat["C", "E", "OR"] <- p_CE
  p_mat["C", "C", "OR"] <- 1 - p_CD - p_CE
  p_mat["C", "D", "OR"] <- p_CD
  # From D
  p_mat["D", "E", "OR"] <- 0
  p_mat["D", "C", "OR"] <- 0
  p_mat["D", "D", "OR"] <- 1
  
  
  # Fill in the matrix (EVAR)
  # p_EC and p_CE will be constant across cycles
  
  # From E
  p_mat["E", "E", "EVAR"] <- 1 - p_EC*(1-effect) - p_ED
  p_mat["E", "C", "EVAR"] <- p_EC*(1-effect)
  p_mat["E", "D", "EVAR"] <- p_ED
  # From C
  p_mat["C", "E", "EVAR"] <- p_CE
  p_mat["C", "C", "EVAR"] <- 1 - p_CD - p_CE
  p_mat["C", "D", "EVAR"] <- p_CD
  # From D
  p_mat["D", "E", "EVAR"] <- 0
  p_mat["D", "C", "EVAR"] <- 0
  p_mat["D", "D", "EVAR"] <- 1
  
  return(p_mat)
}     # end of lookup function


#############################################################################
### Step 3: Create empty matrices to store model outputs (as before)

# Matrix to store numbers of individuals in each health state across cycles
pop <- array(data = NA,
             dim = c(n_states, n_cycles+1, n_treat),   
             dimnames = list(state = states,
                             cycle = NULL,
                             treatment = treat))

# first cycle
pop["E", cycle = 1, ] <- n
pop["C", cycle = 1, ] <- 0
pop["D", cycle = 1, ] <- 0


# Matrix to store cost-effectiveness endpoints
costs <- LYs <- QALYs  <- array(data = NA,
                                dim = c(n_treat, n_cycles+1),
                                dimnames = list(treatment = treat,
                                                cycle = NULL))

# vector to store total life years (LYs), QALYs and costs
total_LYs <- total_QALYs <- total_costs <- setNames(c(NA, NA), treat)


#############################################################################
### Step 4: Re-run the model by replacing p_mat by p_mat_cycle across each cycle 

# outer loop - loop over treatment groups
for (i in 1:n_treat) {      
  
  # set the age 'clock' starting at age0
  age<-age0
  
  # inner loop - loop over cycles 
  for (j in 1:n_cycles) {       
    
    # in each cycle replace p_mat by p_mat_cycle that includes age-related transition probabilities
    p_mat <- p_mat_cycle(p_mat, age, j)
    
    pop[, cycle = j+1, treatment = i] <-     # starts in cycle 2 as cycle 1 is already defined above
      pop[, cycle = j, treatment = i] %*% p_mat[, , treatment = i]
    
    # clock 'ticks' before next cycle
    age <- age + 1
    
  } # end of inner loop
  
  # Life-years - 1 if person alive (i.e states E and C), 0 otherwise (state D)
  LYs[i, ] <- (c(1,1,0) %*% pop[, , treatment = i]) * 1/(1 + dr)^(0:n_cycles)   # cycle 1 = Year 0
  
  # Quality-adjusted life-years (LYs adjusted by the quality of life)
  QALYs[i, ] <- (u_matrix[treatment = i, ] %*% pop[, , treatment = i]) * 1/(1 + dr)^(0:n_cycles)
  
  # Costs
  costs[i, ] <-(c_matrix[treatment = i, ] %*% pop[, , treatment = i]) * 1/(1 + dr)^(0:n_cycles)
  
  total_LYs[i] <- sum(LYs[treatment = i, -1])       # -1 means 'exclude Year 0'
  total_QALYs[i] <- sum(QALYs[treatment = i, -1])
  total_costs[i] <- sum(costs[treatment = i, -1])
  
}  # end of outer loop

# Add one-off cost (per patient) of the intervention
total_costs<-c(total_costs["EVAR"] + c_evar*n, total_costs["OR"] + c_or*n)

# incremental LY
inc_ly <- total_LYs["EVAR"] - total_LYs["OR"]

# incremental QALY
inc_qaly <- total_QALYs["EVAR"] - total_QALYs["OR"]

# Incremental costs 
inc_cost <- total_costs["EVAR"] - total_costs["OR"]

# Incremental net benefit at �30,000/QALY threshold
inb <- inc_qaly*30000-inc_cost

# Incremental cost-effectiveness ratio
icer <- inc_cost/inc_qaly

total_LYs
total_QALYs
total_costs
inc_ly
inc_qaly
inc_cost
inb
icer



#############################################################################
#
### Question 6
#
#############################################################################


rm(list=ls())

# Set working directory and load the dataset
setwd("N:/Manuel Gomes/Teaching/Advanced EE/Practicals/Practicals 3-6")


#############################################################################
### Step 1: Create function that will be used to re-run the model for each parameter value

### chd_mod below is a function of all parameters which values we wish to vary in the
### deterministic sensitivity analysis (listed in Table 2).
### all other parameters are fixed (e.g. age0, dr, c_D, u_D, etc.)

chd_mod <- function(all_params) {      # all_params - set of all parameters 
  
  with(as.list(all_params), {
    
    # treatments
    treat <- c("EVAR", "OR")    # treatments
    n_treat <- length(treat)    # no. treatments
    
    # health states (E: event-free survival, C: CVD event, D: Death)
    states <- c("E", "C", "D")
    n_states <- length(states)  # no. states
    
    # cohort
    n <- 1000                # size of the cohort
    age0 <- 55               # initial age of cohort
    
    # cycles
    n_cycles <- 43           # no. cycles
    
    # Discount rate (same for costs and QALYs)
    dr <- 0.035
    
    # costs for each health state
    
    c_E <- c_E         # cost in E state
    c_C <- c_C         # cost in C state
    c_D <- 0           # cost in D state
    c_evar <- c_evar   # Cost of EVAR treatment (one-off)
    c_or <- c_or       # Cost of Open Repair treatment (one-off)
    
    
    # costs matrix across states and treatment groups
    
    c_matrix <- matrix(
      c(c_E, c_C, c_D, 
        c_E, c_C, c_D),
      byrow = TRUE,
      nrow = n_treat,
      dimnames = list(treat,states))
    
    
    # utilities for each health state
    u_E <- u_E         # utility in E state
    u_C <- u_C         # utility in C state
    u_D <- 0           # utility in D state
    
    # utilities matrix across states and treatment groups
    
    u_matrix <- matrix(
      c(u_E, u_C, u_D,   
        u_E, u_C, u_D),
      byrow = TRUE,
      nrow = n_treat,
      dimnames = list(treat,states))
    
    
    # annual transition probabilities between health states 
    
    p_EC <- p_EC         # transition probability from E to C state
    p_CE <- p_CE         # transition probability from C to E state
    p_ED <- p_ED         # transition probability from E to D state
    p_CD <- p_CD         # transition probability from C to D state
    
    effect<- effect         # effect of treatment (reduces progression)
    
    
    # 6.4.1 create matrix with all transition rates per treatment arm
    
    # initialise transition matrix
    p_mat <- array(data = NA,
                   dim = c(n_states, n_states, n_treat),
                   dimnames = list(from = states,
                                   to = states,
                                   treat))
    
    # Fill in the matrix (Open Repair)
    # From E
    p_mat["E", "E", "OR"] <- 1 - p_EC - p_ED
    p_mat["E", "C", "OR"] <- p_EC
    p_mat["E", "D", "OR"] <- p_ED
    # From C
    p_mat["C", "E", "OR"] <- p_CE
    p_mat["C", "C", "OR"] <- 1 - p_CD - p_CE
    p_mat["C", "D", "OR"] <- p_CD
    # From D
    p_mat["D", "E", "OR"] <- 0
    p_mat["D", "C", "OR"] <- 0
    p_mat["D", "D", "OR"] <- 1
    
    # Fill in the matrix (EVAR)
    # From E
    p_mat["E", "E", "EVAR"] <- 1 - p_EC*(1-effect) - p_ED
    p_mat["E", "C", "EVAR"] <- p_EC*(1-effect)
    p_mat["E", "D", "EVAR"] <- p_ED
    # From C
    p_mat["C", "E", "EVAR"] <- p_CE
    p_mat["C", "C", "EVAR"] <- 1 - p_CD - p_CE
    p_mat["C", "D", "EVAR"] <- p_CD
    # From D
    p_mat["D", "E", "EVAR"] <- 0
    p_mat["D", "C", "EVAR"] <- 0
    p_mat["D", "D", "EVAR"] <- 1
    
    
    # Create empty matrices to store model output
    
    # Matrix to store numbers of individuals in each health state across cycles
    pop <- array(data = NA,
                 dim = c(n_states, n_cycles+1, n_treat),   
                 dimnames = list(state = states,
                                 cycle = NULL,
                                 treatment = treat))
    
    # first cycle
    pop["E", cycle = 1, ] <- n
    pop["C", cycle = 1, ] <- 0
    pop["D", cycle = 1, ] <- 0
    
    
    # Matrix to store cost-effectiveness endpoints
    costs <- LYs <- QALYs  <- array(data = NA,
                                    dim = c(n_treat, n_cycles+1),
                                    dimnames = list(treatment = treat,
                                                    cycle = NULL))
    
    # vector to store total life years (LYs), QALYs and costs
    total_LYs <- total_QALYs <- total_costs <- setNames(c(NA, NA), treat)
    
    
    ### Run the model
    
    # outer loop - loop over treatment groups
    for (i in 1:n_treat) {      
      
      # inner loop - loop over cycles 
      for (j in 1:n_cycles) {       
        
        pop[, cycle = j+1, treatment = i] <-     # starts in cycle 2 as cycle 1 is already defined above
          pop[, cycle = j, treatment = i] %*% p_mat[, , treatment = i]
        
      } # end of inner loop
      
      # Life-years - 1 if person alive (i.e states E and C), 0 otherwise (state D)
      LYs[i, ] <- (c(1,1,0) %*% pop[, , treatment = i]) * 1/(1 + dr)^(0:n_cycles)   # cycle 1 = Year 0
      
      # Quality-adjusted life-years (LYs adjusted by the quality of life)
      QALYs[i, ] <- (u_matrix[treatment = i, ] %*% pop[, , treatment = i]) * 1/(1 + dr)^(0:n_cycles)
      
      # Costs
      costs[i, ] <-(c_matrix[treatment = i, ] %*% pop[, , treatment = i]) * 1/(1 + dr)^(0:n_cycles)
      
      total_LYs[i] <- sum(LYs[treatment = i, -1])       # -1 means 'exclude Year 0'
      total_QALYs[i] <- sum(QALYs[treatment = i, -1])
      total_costs[i] <- sum(costs[treatment = i, -1])
      
    }  # end of outer loop
    
    # Add one-off cost (per patient) of the intervention
    total_costs<-c(total_costs["EVAR"] + c_evar*n, total_costs["OR"] + c_or*n)
    
    # incremental LY
    inc_ly <- total_LYs["EVAR"] - total_LYs["OR"]
    
    # incremental QALY
    inc_qaly <- total_QALYs["EVAR"] - total_QALYs["OR"]
    
    # Incremental costs 
    inc_cost <- total_costs["EVAR"] - total_costs["OR"]
    
    # Incremental net benefit (INB), assuming a �30,000/QALY threshold
    inb <- inc_qaly*30000-inc_cost
    
    # Incremental cost-effectiveness ratio (ICER)
    icer <- inc_cost/inc_qaly
    
    # create dataframe to store all outputs of interest (cost, QALY, NMB, ICER) by treatment arm
    ce <- data.frame(Strategy = treat,
                     Cost = numeric(n_treat),
                     QALY = numeric(n_treat),
                     INB  = numeric(n_treat),
                     ICER = numeric(n_treat),
                     stringsAsFactors = FALSE)
    
    ce[1, c("Cost", "QALY", "INB", "ICER")] <- c(total_costs["EVAR"], total_QALYs["EVAR"], inb, icer)
    ce[2, c("Cost", "QALY", "INB", "ICER")] <- c(total_costs["OR"], total_QALYs["OR"], 0, 0)
    
    return(ce)
    
  })
}     # end of CHD model



#############################################################################
### Step 2: Define range of values for parameters (listed in Table 2)

# parameter values used in the base case (reference point)
base <- list(c_evar=18000, c_or=15500, c_E=500, c_C=2500,u_E=0.8, u_C=0.6,
             p_ED=0.04, p_CD=0.14, p_EC=0.05, p_CE=0.22, effect=0.1)

# parameter range for the DSA (in this case, lower and upper limits)
param_range <- data.frame(
  pars = c("c_evar", "c_or", "c_E", "c_C","u_E", "u_C",
           "p_ED", "p_CD", "p_EC", "p_CE", "effect"),
  min = c(16000, 14000, 0, 1000, 0.7, 0.5, 0.02, 0.09, 0.03, 0.15, 0.07),
  max = c(20000, 17000, 1000, 4000, 0.9, 0.7, 0.06, 0.2, 0.07, 0.3, 0.13))



#############################################################################
### Step 3: run DSA using 'dampack' library

library(dampack)

# 'run_owsa_det' is a function that essentially loops 'chd_mod' over each parameter value
dsa <- run_owsa_det(params_range = param_range,                    # range of parameters for DSA
                    params_basecase = base,                        # base-case parameter values
                    nsamp = 2,                                     # 2 values (lower and upper limits)
                    FUN = chd_mod,                                 # function created above
                    outcomes = c("Cost", "QALY", "INB", "ICER"),   # outputs of interest
                    strategies = c("EVAR", "OR"),                  # treatment arms
                    progress = FALSE)

# DSA results are stored in 'dsa$owsa' (stacked by treatment arm)
dsa$owsa_Cost
dsa$owsa_QALY
dsa$owsa_INB
dsa$owsa_ICER

#############################################################################
### Step 4: Report the results

# there are many ways to do this.
# Option 1: report results in a table (less straightforward to interpret)
# Option 2: plot the results, often using a tornado diagram to help visualisation


# Here I will make use of the 'ggplot2' library but others could be used.
library(ggplot2)
library(plyr)
library(dplyr)
library(tidyverse)

# create dataframe with the outputs of interest (here, let's focus on ICER)
dsa.res <- data.frame(
  pars = c("c_evar", "c_or", "c_E", "c_C","u_E", "u_C",
           "p_ED", "p_CD", "p_EC", "p_CE", "effect"),
  min = NA,    # ICER results from lower limit values
  max = NA,    # ICER results from upper limit values
  dif = NA)    # difference between ICER of lower and upper limits (to sort results by magnitude of CI)

dsa.res[1, 2:4] <- c(dsa$owsa_ICER[1,"outcome_val"],dsa$owsa_ICER[2,"outcome_val"],abs(dsa$owsa_ICER[1,"outcome_val"]-dsa$owsa_ICER[2,"outcome_val"]))
dsa.res[2, 2:4] <- c(dsa$owsa_ICER[5,"outcome_val"],dsa$owsa_ICER[6,"outcome_val"],abs(dsa$owsa_ICER[5,"outcome_val"]-dsa$owsa_ICER[6,"outcome_val"]))
dsa.res[3, 2:4] <- c(dsa$owsa_ICER[9,"outcome_val"],dsa$owsa_ICER[10,"outcome_val"],abs(dsa$owsa_ICER[9,"outcome_val"]-dsa$owsa_ICER[10,"outcome_val"]))
dsa.res[4, 2:4] <- c(dsa$owsa_ICER[13,"outcome_val"],dsa$owsa_ICER[14,"outcome_val"],abs(dsa$owsa_ICER[13,"outcome_val"]-dsa$owsa_ICER[14,"outcome_val"]))
dsa.res[5, 2:4] <- c(dsa$owsa_ICER[17,"outcome_val"],dsa$owsa_ICER[18,"outcome_val"],abs(dsa$owsa_ICER[17,"outcome_val"]-dsa$owsa_ICER[18,"outcome_val"]))
dsa.res[6, 2:4] <- c(dsa$owsa_ICER[21,"outcome_val"],dsa$owsa_ICER[22,"outcome_val"],abs(dsa$owsa_ICER[21,"outcome_val"]-dsa$owsa_ICER[22,"outcome_val"]))
dsa.res[7, 2:4] <- c(dsa$owsa_ICER[25,"outcome_val"],dsa$owsa_ICER[26,"outcome_val"],abs(dsa$owsa_ICER[25,"outcome_val"]-dsa$owsa_ICER[26,"outcome_val"]))
dsa.res[8, 2:4] <- c(dsa$owsa_ICER[29,"outcome_val"],dsa$owsa_ICER[30,"outcome_val"],abs(dsa$owsa_ICER[29,"outcome_val"]-dsa$owsa_ICER[30,"outcome_val"]))
dsa.res[9, 2:4] <- c(dsa$owsa_ICER[33,"outcome_val"],dsa$owsa_ICER[34,"outcome_val"],abs(dsa$owsa_ICER[33,"outcome_val"]-dsa$owsa_ICER[34,"outcome_val"]))
dsa.res[10, 2:4] <- c(dsa$owsa_ICER[37,"outcome_val"],dsa$owsa_ICER[38,"outcome_val"],abs(dsa$owsa_ICER[37,"outcome_val"]-dsa$owsa_ICER[38,"outcome_val"]))
dsa.res[11, 2:4] <- c(dsa$owsa_ICER[41,"outcome_val"],dsa$owsa_ICER[42,"outcome_val"],abs(dsa$owsa_ICER[41,"outcome_val"]-dsa$owsa_ICER[42,"outcome_val"]))

# ICER from base-case
base.case <- 19374

# sort results (from largest to narrowest) of lower-upper ICER difference
order.pars <- dsa.res %>% arrange(dif) %>%
  mutate(pars=factor(x=pars, levels=pars)) %>%
  select(pars) %>% unlist() %>% levels()

# width of columns in plot (value between 0 and 1)
width <- 0.95

# get data frame in shape for ggplot and geom_rect
tornado <- dsa.res %>% 
  gather(key='type', value='output.value', min:max) %>%   # gather columns min and max into a single column 
  select(pars, type, output.value, dif) %>%               # reorder columns
  mutate(pars=factor(pars, levels=order.pars),            # create the columns for geom_rect
         ymin=pmin(output.value, base.case),
         ymax=pmax(output.value, base.case),
         xmin=as.numeric(pars)-width/2,
         xmax=as.numeric(pars)+width/2)

# create plot
png(width = 960, height = 540)
ggplot() + geom_rect(data = tornado, aes(ymax=ymax, ymin=ymin, xmax=xmax, xmin=xmin, fill=type)) + 
           theme_bw() + theme(axis.title=element_text(size = 16), legend.text=element_text(size=16),
           axis.text=element_text(size=16), legend.title = element_blank(), legend.position = 'bottom') + 
           ylab("ICER") + geom_hline(yintercept = base.case) +
           scale_x_continuous(breaks = c(1:length(order.pars)), labels = order.pars) + coord_flip() 

dev.off()    # plot will be stored in your working directory



#############################################################################
#
### Question 7
#
#############################################################################

# two-way DSA will combine parameter values for 'c_evar' and 'c_or' 

two_param_range <- data.frame(pars = c("c_evar", "c_or"),
                                   min = c(16000, 14000),
                                   max = c(20000, 17000))

# 'run_twsa_det' is similar to 'run_owsa_det'
two_dsa <- run_twsa_det(params_range = two_param_range,            # range of parameters for two_DSA
                    params_basecase = base,                        # base-case parameter values
                    nsamp = 10,                                    # 10 values (between lower and upper limits)
                    FUN = chd_mod,                                 # same function created above
                    outcomes = c("Cost", "QALY", "INB", "ICER"),   # outputs of interest
                    strategies = c("EVAR", "OR"),                  # treatment arms
                    progress = FALSE)

# DSA results are stored as previously
twsa_INB<-two_dsa$twsa_INB

# report results using two-way SA plot
plot(twsa_INB, col = "bw", txtsize=16)


#############################################################################
### 
### GLBH0046: Advanced Economic Evaluation
###
### Practical 7: Probabilistic sensitivity analysis
###
#############################################################################


rm(list=ls())

# Set working directory and load the dataset
setwd("N:/Manuel Gomes/Teaching/Advanced EE/Practicals/Practicals 3-6")

set.seed(20910)  # Set random number generator -> ensures simulations can be reproduced

#############################################################################
### Question 3
#############################################################################

# Plot each distribution in Table 1 and check plausibility

# EVAR costs
c_evar_dist<-rgamma(n=1000, shape=100, scale=180) 
hist(c_evar_dist)

# Open Repair costs
c_or_dist<-rgamma(n=1000, shape=100, scale=155) 
hist(c_or_dist)

# Costs of E state
c_E_dist<-rgamma(n=1000, shape=100, scale=5) 
c_E_dist1<-rgamma(n=1000, shape=25, scale=20) 

par(mfrow=c(1,2), cex.lab=1.5, cex.axis=1.5, cex.main=1.5)
hist(c_E_dist, main="SE=1/10 mean")
hist(c_E_dist1, main="SE=1/5 mean")
dev.off()

# Costs of C state
c_C_dist<-rgamma(n=1000, shape=100, scale=25) 
dev.off()       # reset par() function
hist(c_C_dist)

# Utility of E state
u_E_dist<-rbeta(n=1000, shape1=19.2, shape2=4.8) 
hist(u_E_dist)

# Utility of C state
u_C_dist<-rbeta(n=1000, shape1=39.4, shape2=26.3) 
hist(u_C_dist)

# transition probability p_ED
p_ED_dist<-rbeta(n=1000, shape1=15.3, shape2=367.7) 
hist(p_ED_dist)

# transition probability p_CD
p_CD_dist<-rbeta(n=1000, shape1=42, shape2=258) 
hist(p_CD_dist)

# transition probability p_EC
p_EC_dist<-rbeta(n=1000, shape1=23.7, shape2=450.3) 
hist(p_EC_dist)

# transition probability p_EC
p_EC_dist<-rbeta(n=1000, shape1=23.7, shape2=450.3) 
hist(p_EC_dist)

# Effect parameter
effect_dist<-rlnorm(n=1000, meanlog=log(0.1), sdlog=0.0686) 
effect_dist1<-rlnorm(n=1000, meanlog=log(0.1), sdlog=0.1) 

par(mfrow=c(1,2), cex.lab=1.5, cex.axis=1.5, cex.main=1.5)
hist(effect_dist, main="sdlog=0.068")
hist(effect_dist1, main="sdlog=0.1")

# transition probability p_CE
p_CE_dist<-rbeta(n=1000, shape1=94.2, shape2=333.8) 
dev.off()       # reset par() function
hist(p_CE_dist)



#############################################################################
### Question 4
#############################################################################


#############################################################################
### Step 1: Create function that will be used to re-run the model for each PSA value

### chd_mod below is a function of all parameters which values we wish to vary in the
### deterministic sensitivity analysis (listed in Table 2).
### all other parameters are fixed (e.g. age0, dr, c_D, u_D, etc.)

chd_mod <- function(c_evar, c_or, c_E, c_C,u_E, u_C,
                    p_ED, p_CD, p_EC, p_CE, effect, wtp) {       

    
    # treatments
    treat <- c("EVAR", "OR")    # treatments
    n_treat <- length(treat)    # no. treatments
    
    # health states (E: event-free survival, C: CVD event, D: Death)
    states <- c("E", "C", "D")
    n_states <- length(states)  # no. states
    
    # cohort
    n <- 1000                # size of the cohort
    age0 <- 55               # initial age of cohort
    
    # cycles
    n_cycles <- 43           # no. cycles
    
    # Discount rate (same for costs and QALYs)
    dr <- 0.035
    
    # costs for each health state
    
    c_E <- c_E         # cost in E state
    c_C <- c_C         # cost in C state
    c_D <- 0           # cost in D state
    c_evar <- c_evar   # Cost of EVAR treatment (one-off)
    c_or <- c_or       # Cost of Open Repair treatment (one-off)
    
    
    # costs matrix across states and treatment groups
    
    c_matrix <- matrix(
      c(c_E, c_C, c_D, 
        c_E, c_C, c_D),
      byrow = TRUE,
      nrow = n_treat,
      dimnames = list(treat,states))
    
    
    # utilities for each health state
    u_E <- u_E         # utility in E state
    u_C <- u_C         # utility in C state
    u_D <- 0           # utility in D state
    
    # utilities matrix across states and treatment groups
    
    u_matrix <- matrix(
      c(u_E, u_C, u_D,   
        u_E, u_C, u_D),
      byrow = TRUE,
      nrow = n_treat,
      dimnames = list(treat,states))
    
    
    # annual transition probabilities between health states 
    
    p_EC <- p_EC         # transition probability from E to C state
    p_CE <- p_CE         # transition probability from C to E state
    p_ED <- p_ED         # transition probability from E to D state
    p_CD <- p_CD         # transition probability from C to D state
    
    effect<- effect         # effect of treatment (reduces progression)
    
    
    # 6.4.1 create matrix with all transition rates per treatment arm
    
    # initialise transition matrix
    p_mat <- array(data = NA,
                   dim = c(n_states, n_states, n_treat),
                   dimnames = list(from = states,
                                   to = states,
                                   treat))
    
    # Fill in the matrix (Open Repair)
    # From E
    p_mat["E", "E", "OR"] <- 1 - p_EC - p_ED
    p_mat["E", "C", "OR"] <- p_EC
    p_mat["E", "D", "OR"] <- p_ED
    # From C
    p_mat["C", "E", "OR"] <- p_CE
    p_mat["C", "C", "OR"] <- 1 - p_CD - p_CE
    p_mat["C", "D", "OR"] <- p_CD
    # From D
    p_mat["D", "E", "OR"] <- 0
    p_mat["D", "C", "OR"] <- 0
    p_mat["D", "D", "OR"] <- 1
    
    # Fill in the matrix (EVAR)
    # From E
    p_mat["E", "E", "EVAR"] <- 1 - p_EC*(1-effect) - p_ED
    p_mat["E", "C", "EVAR"] <- p_EC*(1-effect)
    p_mat["E", "D", "EVAR"] <- p_ED
    # From C
    p_mat["C", "E", "EVAR"] <- p_CE
    p_mat["C", "C", "EVAR"] <- 1 - p_CD - p_CE
    p_mat["C", "D", "EVAR"] <- p_CD
    # From D
    p_mat["D", "E", "EVAR"] <- 0
    p_mat["D", "C", "EVAR"] <- 0
    p_mat["D", "D", "EVAR"] <- 1
    
    
    # Create empty matrices to store model output
    
    # Matrix to store numbers of individuals in each health state across cycles
    pop <- array(data = NA,
                 dim = c(n_states, n_cycles+1, n_treat),   
                 dimnames = list(state = states,
                                 cycle = NULL,
                                 treatment = treat))
    
    # first cycle
    pop["E", cycle = 1, ] <- n
    pop["C", cycle = 1, ] <- 0
    pop["D", cycle = 1, ] <- 0
    
    
    # Matrix to store cost-effectiveness endpoints
    costs <- LYs <- QALYs  <- array(data = NA,
                                    dim = c(n_treat, n_cycles+1),
                                    dimnames = list(treatment = treat,
                                                    cycle = NULL))
    
    # vector to store total life years (LYs), QALYs and costs
    total_LYs <- total_QALYs <- total_costs <- setNames(c(NA, NA), treat)
    
    
    ### Run the model
    
    # outer loop - loop over treatment groups
    for (i in 1:n_treat) {      
      
      # inner loop - loop over cycles 
      for (j in 1:n_cycles) {       
        
        pop[, cycle = j+1, treatment = i] <-     # starts in cycle 2 as cycle 1 is already defined above
          pop[, cycle = j, treatment = i] %*% p_mat[, , treatment = i]
        
      } # end of inner loop
      
      # Life-years - 1 if person alive (i.e states E and C), 0 otherwise (state D)
      LYs[i, ] <- (c(1,1,0) %*% pop[, , treatment = i]) * 1/(1 + dr)^(0:n_cycles)   # cycle 1 = Year 0
      
      # Quality-adjusted life-years (LYs adjusted by the quality of life)
      QALYs[i, ] <- (u_matrix[treatment = i, ] %*% pop[, , treatment = i]) * 1/(1 + dr)^(0:n_cycles)
      
      # Costs
      costs[i, ] <-(c_matrix[treatment = i, ] %*% pop[, , treatment = i]) * 1/(1 + dr)^(0:n_cycles)
      
      total_LYs[i] <- sum(LYs[treatment = i, -1])       # -1 means 'exclude Year 0'
      total_QALYs[i] <- sum(QALYs[treatment = i, -1])
      total_costs[i] <- sum(costs[treatment = i, -1])
      
    }  # end of outer loop
    
    # Add one-off cost (per patient) of the intervention
    total_costs<-c(total_costs["EVAR"] + c_evar*n, total_costs["OR"] + c_or*n)
    
    # incremental LY
    inc_ly <- total_LYs["EVAR"] - total_LYs["OR"]
    
    # incremental QALY
    inc_qaly <- total_QALYs["EVAR"] - total_QALYs["OR"]
    
    # Incremental costs 
    inc_cost <- total_costs["EVAR"] - total_costs["OR"]
    
    # net monetary benefit at �30,000 per QALY - will be needed for value of information analysis (VOI)
    nb.evar <- total_QALYs["EVAR"]*wtp - total_costs["EVAR"]
    nb.or   <- total_QALYs["OR"]*wtp - total_costs["OR"]
    
    # Incremental net benefit (INB)
    inb <- inc_qaly*wtp-inc_cost
    
    # Cost-effective: =1 if INB>0, 0 otherwise (could also be calculated as nb.evar-nb.or)
    pce <- ifelse(inb>0,1,0)
    
    # Incremental cost-effectiveness ratio (ICER)
    icer <- inc_cost/inc_qaly
    
    ce <- c(inc_qaly,inc_cost,nb.evar,nb.or,pce)

    return(ce)
    
  }   # end of CHD model


#############################################################################
### Step 2: Create an empty matrix to store all the outputs of interest

 
M<-1000        # define number of PSA runs

# Create an empty matrix to store outputs of interest
psa <- matrix(NA, nrow = M, ncol = 5,
           dimnames = list(NULL, c("inc_qaly","inc_cost", "nb.evar", "nb.or", "pce")))


#############################################################################
### Step 3: Re-run chd_mod M=1000 times

for (i in 1:M) {
  
 psa.res <- chd_mod(
          c_evar=c_evar_dist[i],
          c_or  =c_or_dist[i],
          c_E   =c_E_dist1[i],
          c_C   =c_C_dist[i],
          u_E   =u_E_dist[i],
          u_C   =u_C_dist[i],
          p_ED  =p_ED_dist[i],
          p_CD  =p_CD_dist[i],
          p_EC  =p_EC_dist[i],
          p_CE  =p_CE_dist[i],
          effect=effect_dist1[i],
          wtp   =30000)

 psa [i,] <- psa.res
}


#############################################################################
### Step 4: Plot results in the cost-effectiveness (CE) plane.

n<-1000                     # cohort size
wtp<-30000                  # willingness-to-pay threshold for QALY gain
base_case<-c(121, 2351145)  # incremental QALY and incremental cost from base-case

# plot results in the CE plane
par(las=1)
plot(x = psa[,1]/n, y = psa[,2]/n,
     main=" ", xlab="", ylab="", 
     xlim = c(0, 0.4), ylim = c(-5000, 10000),
     pch=19, cex=1.2, col="darkslategray", axes=F )
points(x=base_case[1]/n, y=base_case[2]/n, col='red', cex=1.5, pch=16)
axis(1, pos=0, cex.axis=1.5)
axis(2, pos=0, cex.axis=1.5)
abline(a = 0, b = wtp, lty='dotted', lwd = 2) # Willingness-to-pay threshold
text(0.35, 7500, "WTP - �30,000", cex=1.5)
mtext(side=1, line=1, "Incremental QALY", cex=1.5)
mtext(side=2, line=3, "Incremental cost", cex=1.5, las=0)


#############################################################################
### Question 5
#############################################################################


#############################################################################
###  Report cost-effectiveness acceptability curve (CEAC)


### Plot CEAC

wtp   <- seq(0,100000, length=21)   # Willingness-to-pay (WTP) values for QALY gain
n_wtp <- length(wtp)                # no. Of WTP

ceac<-c()


for (j in 1:n_wtp) {    # outer loop - across alternative WTP values
  
  for (i in 1:M) {      # inner loop - across PSA values
    
    psa.res <- chd_mod(
      c_evar=c_evar_dist[i],
      c_or  =c_or_dist[i],
      c_E   =c_E_dist1[i],
      c_C   =c_C_dist[i],
      u_E   =u_E_dist[i],
      u_C   =u_C_dist[i],
      p_ED  =p_ED_dist[i],
      p_CD  =p_CD_dist[i],
      p_EC  =p_EC_dist[i],
      p_CE  =p_CE_dist[i],
      effect=effect_dist1[i],
      wtp   = wtp[j])
    
    psa [i,] <- psa.res
  }
  
  
  ceac[j] <-  sum(psa[,"pce"])/M           # % PSA runs for which INB>0
  
}

plot(wtp, ceac, type="l", ylim=c(0,1), main=" ", col = "dark red", cex.lab = 1.5,
           xaxt='n', yaxt='n',
           ylab="Prob EVAR being cost-effective", xlab="Willingness to pay for a QALY (�, thousands)" )
axis(1,at=c(0,10000,20000,30000,40000,50000,60000,70000,80000,90000,100000), labels=c(0,10,20,30,40,50,60,70,80,90,100),cex.axis=1.5)
axis(2,at=seq(0.1,.9,0.2), labels=seq(0.1,0.9,0.2), cex.axis=1.5, las=1)
abline(v=20000, lty=3, col="grey")
abline(v=30000, lty=3, col="grey")



#############################################################################
### Question 6
#############################################################################


#############################################################################
###  Calculate expected value of perfect information (EVPI)


### Plot EVPI

evpi <-c()

for (j in 1:n_wtp) {    # outer loop - across alternative WTP values
  
  for (i in 1:M) {      # inner loop - across PSA values
    
    psa.res <- chd_mod(
      c_evar=c_evar_dist[i],
      c_or  =c_or_dist[i],
      c_E   =c_E_dist1[i],
      c_C   =c_C_dist[i],
      u_E   =u_E_dist[i],
      u_C   =u_C_dist[i],
      p_ED  =p_ED_dist[i],
      p_CD  =p_CD_dist[i],
      p_EC  =p_EC_dist[i],
      p_CE  =p_CE_dist[i],
      effect=effect_dist1[i],
      wtp   = wtp[j])
    
    psa [i,] <- psa.res
  }
  
  nb <- psa[,3:4]  # Net benefit matrix
  
  # EVPI=E(max NB)- max E(NB)
  # E(max NB) - average of the maximum benefit between EVAR or OR across M runs
  # max E(NB) - maximum of the average net benefit between EVAR and OR
  
  evpi[j] <-  mean(apply(nb, 1, max)) - max(colMeans(nb))           
  
}

par(mar = c(5,7,4,2) + 0.1) # increase axis space
par(mgp=c(3.5,1,0))           # adjust space between label and axis
plot(wtp, evpi, type="l", main=" ", col = "dark red", xaxt='n', yaxt='n', cex.lab = 1.5,
     ylab="Population EVPI (�, thousands)", xlab="Willingness to pay for a QALY (�, thousands)" )
axis(1,at=c(0,10000,20000,30000,40000,50000,60000,70000,80000,90000,100000), labels=c(0,10,20,30,40,50,60,70,80,90,100), cex.axis=1.5)
axis(2,at=c(0,1e+5,2e+5,3e+5,4e+5,5e+5,6e+5,7e+5,8e+5,9e+5,1e+6),labels=c(0,100,200,300,400,500,600,700,800,900,1000), cex.axis=1.5, las=1)
abline(h=500000, lty=3, col="grey")
04-13 17:48