|
@@ -0,0 +1,109 @@
|
|
|
|
|
+# We will use cycles from 0 to 100
|
|
|
|
|
+cycles <- 0:100
|
|
|
|
|
+
|
|
|
|
|
+# Create an array for the state membership
|
|
|
|
|
+state_membership <- array(NA_real_, c(length(cycles), 3), list(cycle = cycles, state = c("Healthy", "Diseased", "Dead")))
|
|
|
|
|
+state_membership[1, ] <- c(1, 0, 0)
|
|
|
|
|
+
|
|
|
|
|
+# Define the survival model parameters
|
|
|
|
|
+# - Healthy to Diseased
|
|
|
|
|
+lambda_inc <- 2e-5
|
|
|
|
|
+gamma_inc <- 2.5
|
|
|
|
|
+# - Healthy to Dead
|
|
|
|
|
+a_general <- 0.2
|
|
|
|
|
+b_general <- 1e-7
|
|
|
|
|
+# - Diseased to Dead
|
|
|
|
|
+lambda_surv <- 0.2
|
|
|
|
|
+gamma_surv <- 0.5
|
|
|
|
|
+
|
|
|
|
|
+# Calculate the hazard rates for the transitions out of the Healthy state
|
|
|
|
|
+healthy_haz <- array(NA_real_, c(length(cycles), 2), list(cycle = cycles, to = c("Diseased", "Dead")))
|
|
|
|
|
+healthy_haz[, 1] <- lambda_inc * ((cycles + 1) ^ gamma_inc - cycles ^ gamma_inc)
|
|
|
|
|
+healthy_haz[, 2] <- b_general / a_general * (exp(a_general * (cycles + 1)) - exp(a_general * cycles))
|
|
|
|
|
+
|
|
|
|
|
+# Create an array for transition probabilities in each cycle
|
|
|
|
|
+transition_probs <- array(NA_real_, c(length(cycles), 3), list(cycle = cycles, transition = c("Healthy->Diseased", "Healthy->Dead", "Diseased->Dead")))
|
|
|
|
|
+
|
|
|
|
|
+# The transition probabilities for the Healthy state can be calculated already
|
|
|
|
|
+transition_probs[, 1:2] <- healthy_haz / rowSums(healthy_haz) * (1 - exp(-rowSums(healthy_haz)))
|
|
|
|
|
+
|
|
|
|
|
+# Create an array for the moments of the overall CSSTD in each cycle
|
|
|
|
|
+csstd_moments <- array(NA_real_, c(length(cycles), 5), list(cycle = cycles, moment = c("1st raw (mean)", "2nd raw", "3rd raw", "2nd central (variance)", "3rd central")))
|
|
|
|
|
+
|
|
|
|
|
+# Create an array for the weights of the two components in the CSSTD
|
|
|
|
|
+component_weights <- array(NA_real_, c(length(cycles), 2), list(cycle = cycles, component = c("Remaining in state", "Entering state")))
|
|
|
|
|
+
|
|
|
|
|
+# Create an array for the moments for the first component (remaining in the state)
|
|
|
|
|
+remaining_moments <- array(NA_real_, c(length(cycles), 6), list(cycle = cycles, moment = c("1st raw (mean)", "1st around 1", "2nd around 1", "3rd around 1", "2nd central (variance)", "3rd central")))
|
|
|
|
|
+
|
|
|
|
|
+# Create a vector for the probability for remaining in the Diseased state
|
|
|
|
|
+ephi <- rep(NA_real_, length(cycles))
|
|
|
|
|
+
|
|
|
|
|
+# Create an array for rho
|
|
|
|
|
+rho <- array(NA_real_, c(length(cycles), 3), list(cycle = cycles, derivative = 0:2))
|
|
|
|
|
+
|
|
|
|
|
+# Create an expression for phi(s), the conditional probability of staying in the state one more cycle
|
|
|
|
|
+# Note: We aren't evaluating this yet - it is just symbolic
|
|
|
|
|
+phi <- expression( exp(-lambda_surv * ((s + 1) ^ gamma_surv - s ^ gamma_surv)) )
|
|
|
|
|
+
|
|
|
|
|
+# Create expressions for the first two derivatives of phi(s)
|
|
|
|
|
+dphi <- D( phi, "s")
|
|
|
|
|
+d2phi <- D( dphi, "s")
|
|
|
|
|
+d3phi <- D(d2phi, "s")
|
|
|
|
|
+
|
|
|
|
|
+# Initialise the model
|
|
|
|
|
+csstd_moments[1, ] <- 0
|
|
|
|
|
+ephi[1] <- eval(phi, list(s = 0))
|
|
|
|
|
+transition_probs[1, 3] <- 1 - ephi[1]
|
|
|
|
|
+rho[1, 1] <- 1
|
|
|
|
|
+rho[1, 2:3] <- 0
|
|
|
|
|
+
|
|
|
|
|
+# Iterate through the cycles
|
|
|
|
|
+for (i in 2:length(cycles)) {
|
|
|
|
|
+
|
|
|
|
|
+ # Update state membership
|
|
|
|
|
+ state_membership[i, 1] <- state_membership[i - 1, 1] * (1 - sum(transition_probs[i - 1, 1:2]))
|
|
|
|
|
+ state_membership[i, 2] <- state_membership[i - 1, 1] * transition_probs[i - 1, 1] +
|
|
|
|
|
+ state_membership[i - 1, 2] * (1 - transition_probs[i - 1, 3])
|
|
|
|
|
+ state_membership[i, 3] <- state_membership[i - 1, 1] * transition_probs[i - 1, 2] +
|
|
|
|
|
+ state_membership[i - 1, 2] * transition_probs[i - 1, 3] +
|
|
|
|
|
+ state_membership[i - 1, 3]
|
|
|
|
|
+
|
|
|
|
|
+ # Calculate weights
|
|
|
|
|
+ component_weights[i, 2] <- state_membership[i - 1, 1] * transition_probs[i - 1, 1] / state_membership[i, 2]
|
|
|
|
|
+ component_weights[i, 1] <- 1 - component_weights[i, 2]
|
|
|
|
|
+
|
|
|
|
|
+ # Calculate moments for those remaining in the state (since the previous cycle)
|
|
|
|
|
+ remaining_moments[i, 1] <- 1 + csstd_moments[i - 1, "1st raw (mean)"] * rho[i - 1, 1] +
|
|
|
|
|
+ (csstd_moments[i - 1, "2nd raw"] - csstd_moments[i - 1, "1st raw (mean)"] ^ 2) * rho[i - 1, 2] +
|
|
|
|
|
+ (csstd_moments[i - 1, "3rd raw"] - 2 * csstd_moments[i - 1, "1st raw (mean)"] * csstd_moments[i - 1, "2nd raw"] + csstd_moments[i - 1, "1st raw (mean)"] ^ 3) * rho[i - 1, 3] / 2
|
|
|
|
|
+ remaining_moments[i, 2] <- remaining_moments[i, 1] - 1
|
|
|
|
|
+ remaining_moments[i, 3] <- csstd_moments[i - 1, "2nd raw"] * rho[i - 1, 1] +
|
|
|
|
|
+ (csstd_moments[i - 1, "3rd raw"] - csstd_moments[i - 1, "1st raw (mean)"] * csstd_moments[i - 1, "2nd raw"]) * rho[i - 1, 2]
|
|
|
|
|
+ remaining_moments[i, 4] <- csstd_moments[i - 1, "3rd raw"] * rho[i - 1, 1]
|
|
|
|
|
+ remaining_moments[i, 5] <- remaining_moments[i, 3] - (1 - remaining_moments[i, 1]) ^ 2
|
|
|
|
|
+ remaining_moments[i, 6] <- remaining_moments[i, 4] + 3 * remaining_moments[i, 3] * (1 - remaining_moments[i, 1]) - 2 * (1 - remaining_moments[i, 1]) ^ 3
|
|
|
|
|
+
|
|
|
|
|
+ # Calculate overall CSSTD moments
|
|
|
|
|
+ csstd_moments[i, 1] <- component_weights[i, 1] * remaining_moments[i, 1] + component_weights[i, 2] * 0.5
|
|
|
|
|
+ temp <- remaining_moments[i, 1] - csstd_moments[i, 1]
|
|
|
|
|
+ csstd_moments[i, 4] <- component_weights[i, 1] * (temp^2 + remaining_moments[i, 5]) + component_weights[i, 2] * (0.5 - csstd_moments[i, 1]) ^ 2
|
|
|
|
|
+ csstd_moments[i, 5] <- component_weights[i, 1] * (temp^3 + 3 * remaining_moments[i, 5] * temp + remaining_moments[i, 6]) + component_weights[i, 2] * (0.5 - csstd_moments[i, 1])^3
|
|
|
|
|
+ csstd_moments[i, 2] <- csstd_moments[i, 1] ^ 2 + csstd_moments[i, 4]
|
|
|
|
|
+ csstd_moments[i, 3] <- csstd_moments[i, 1] ^ 3 + 3 * csstd_moments[i, 4] * csstd_moments[i, 1] + csstd_moments[i, 5]
|
|
|
|
|
+
|
|
|
|
|
+ # Calculate E[phi(s)]
|
|
|
|
|
+ mu <- csstd_moments[i, 1]
|
|
|
|
|
+ phi_eval <- eval( phi, list(s = mu))
|
|
|
|
|
+ dphi_eval <- eval( dphi, list(s = mu))
|
|
|
|
|
+ d2phi_eval <- eval(d2phi, list(s = mu))
|
|
|
|
|
+ d3phi_eval <- eval(d3phi, list(s = mu))
|
|
|
|
|
+
|
|
|
|
|
+ ephi[i] <- phi_eval + d2phi_eval / 2 * csstd_moments[i, "2nd central (variance)"] + d3phi_eval / 6 * csstd_moments[i, "3rd central"]
|
|
|
|
|
+ transition_probs[i, 3] <- 1 - ephi[i]
|
|
|
|
|
+
|
|
|
|
|
+ # Calculate rho and derivatives
|
|
|
|
|
+ rho[i, 1] <- phi_eval / ephi[i]
|
|
|
|
|
+ rho[i, 2] <- dphi_eval / ephi[i]
|
|
|
|
|
+ rho[i, 3] <- d2phi_eval / ephi[i]
|
|
|
|
|
+}
|