time-dependent-CSSTD.R 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. # We will use cycles from 0 to 100
  2. cycles <- 0:100
  3. # Create an array for the state membership
  4. state_membership <- array(NA_real_, c(length(cycles), 3), list(cycle = cycles, state = c("Healthy", "Diseased", "Dead")))
  5. state_membership[1, ] <- c(1, 0, 0)
  6. # Define the survival model parameters
  7. # - Healthy to Diseased
  8. lambda_inc <- 2e-5
  9. gamma_inc <- 2.5
  10. # - Healthy to Dead
  11. a_general <- 0.2
  12. b_general <- 1e-7
  13. # - Diseased to Dead
  14. lambda_surv <- 0.2
  15. gamma_surv <- 0.5
  16. # Calculate the hazard rates for the transitions out of the Healthy state
  17. healthy_haz <- array(NA_real_, c(length(cycles), 2), list(cycle = cycles, to = c("Diseased", "Dead")))
  18. healthy_haz[, 1] <- lambda_inc * ((cycles + 1) ^ gamma_inc - cycles ^ gamma_inc)
  19. healthy_haz[, 2] <- b_general / a_general * (exp(a_general * (cycles + 1)) - exp(a_general * cycles))
  20. # Create an array for transition probabilities in each cycle
  21. transition_probs <- array(NA_real_, c(length(cycles), 3), list(cycle = cycles, transition = c("Healthy->Diseased", "Healthy->Dead", "Diseased->Dead")))
  22. # The transition probabilities for the Healthy state can be calculated already
  23. transition_probs[, 1:2] <- healthy_haz / rowSums(healthy_haz) * (1 - exp(-rowSums(healthy_haz)))
  24. # Create an array for the moments of the overall CSSTD in each cycle
  25. 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")))
  26. # Create an array for the weights of the two components in the CSSTD
  27. component_weights <- array(NA_real_, c(length(cycles), 2), list(cycle = cycles, component = c("Remaining in state", "Entering state")))
  28. # Create an array for the moments for the first component (remaining in the state)
  29. 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")))
  30. # Create a vector for the probability for remaining in the Diseased state
  31. ephi <- rep(NA_real_, length(cycles))
  32. # Create an array for rho
  33. rho <- array(NA_real_, c(length(cycles), 3), list(cycle = cycles, derivative = 0:2))
  34. # Create an expression for phi(s), the conditional probability of staying in the state one more cycle
  35. # Note: We aren't evaluating this yet - it is just symbolic
  36. phi <- expression( exp(-lambda_surv * ((s + 1) ^ gamma_surv - s ^ gamma_surv)) )
  37. # Create expressions for the first two derivatives of phi(s)
  38. dphi <- D( phi, "s")
  39. d2phi <- D( dphi, "s")
  40. d3phi <- D(d2phi, "s")
  41. # Initialise the model
  42. csstd_moments[1, ] <- 0
  43. ephi[1] <- eval(phi, list(s = 0))
  44. transition_probs[1, 3] <- 1 - ephi[1]
  45. rho[1, 1] <- 1
  46. rho[1, 2:3] <- 0
  47. # Iterate through the cycles
  48. for (i in 2:length(cycles)) {
  49. # Update state membership
  50. state_membership[i, 1] <- state_membership[i - 1, 1] * (1 - sum(transition_probs[i - 1, 1:2]))
  51. state_membership[i, 2] <- state_membership[i - 1, 1] * transition_probs[i - 1, 1] +
  52. state_membership[i - 1, 2] * (1 - transition_probs[i - 1, 3])
  53. state_membership[i, 3] <- state_membership[i - 1, 1] * transition_probs[i - 1, 2] +
  54. state_membership[i - 1, 2] * transition_probs[i - 1, 3] +
  55. state_membership[i - 1, 3]
  56. # Calculate weights
  57. component_weights[i, 2] <- state_membership[i - 1, 1] * transition_probs[i - 1, 1] / state_membership[i, 2]
  58. component_weights[i, 1] <- 1 - component_weights[i, 2]
  59. # Calculate moments for those remaining in the state (since the previous cycle)
  60. remaining_moments[i, 1] <- 1 + csstd_moments[i - 1, "1st raw (mean)"] * rho[i - 1, 1] +
  61. (csstd_moments[i - 1, "2nd raw"] - csstd_moments[i - 1, "1st raw (mean)"] ^ 2) * rho[i - 1, 2] +
  62. (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
  63. remaining_moments[i, 2] <- remaining_moments[i, 1] - 1
  64. remaining_moments[i, 3] <- csstd_moments[i - 1, "2nd raw"] * rho[i - 1, 1] +
  65. (csstd_moments[i - 1, "3rd raw"] - csstd_moments[i - 1, "1st raw (mean)"] * csstd_moments[i - 1, "2nd raw"]) * rho[i - 1, 2]
  66. remaining_moments[i, 4] <- csstd_moments[i - 1, "3rd raw"] * rho[i - 1, 1]
  67. remaining_moments[i, 5] <- remaining_moments[i, 3] - (1 - remaining_moments[i, 1]) ^ 2
  68. 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
  69. # Calculate overall CSSTD moments
  70. csstd_moments[i, 1] <- component_weights[i, 1] * remaining_moments[i, 1] + component_weights[i, 2] * 0.5
  71. temp <- remaining_moments[i, 1] - csstd_moments[i, 1]
  72. 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
  73. 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
  74. csstd_moments[i, 2] <- csstd_moments[i, 1] ^ 2 + csstd_moments[i, 4]
  75. csstd_moments[i, 3] <- csstd_moments[i, 1] ^ 3 + 3 * csstd_moments[i, 4] * csstd_moments[i, 1] + csstd_moments[i, 5]
  76. # Calculate E[phi(s)]
  77. mu <- csstd_moments[i, 1]
  78. phi_eval <- eval( phi, list(s = mu))
  79. dphi_eval <- eval( dphi, list(s = mu))
  80. d2phi_eval <- eval(d2phi, list(s = mu))
  81. d3phi_eval <- eval(d3phi, list(s = mu))
  82. ephi[i] <- phi_eval + d2phi_eval / 2 * csstd_moments[i, "2nd central (variance)"] + d3phi_eval / 6 * csstd_moments[i, "3rd central"]
  83. transition_probs[i, 3] <- 1 - ephi[i]
  84. # Calculate rho and derivatives
  85. rho[i, 1] <- phi_eval / ephi[i]
  86. rho[i, 2] <- dphi_eval / ephi[i]
  87. rho[i, 3] <- d2phi_eval / ephi[i]
  88. }