def transition_probabilities(mortality_multiplier): """2b. Construct transition probabilities between disease severities There are three disease states: mild, severe and critical. - Mild represents sub-hospitalization. - Severe is hospitalization. - Critical is ICU. The key results of this section are: - p_mild_severe: N_AGES x 2 x 2 matrix. For each age and comorbidity state (length two bool vector indicating whether the individual has diabetes and/or hypertension), what is the probability of the individual transitioning from the mild to severe state. - p_severe_critical, p_critical_death are the same for the other state transitions. All of these probabilities are proportional to the base progression rate for an (age, diabetes, hypertension) state which is stored in p_death_target and estimated via logistic regression. """ # N_AGES vector: The probability of transitioning from the mild to # severe state for a patient of age i is p_mild_severe_cdc[i]. We will match # these overall probabilities. # Source: https://www.cdc.gov/mmwr/volumes/69/wr/mm6912e2.htm?s_cid=mm6912e2_w#T1_down # Using the lower bounds for probability of hospitalization, since that's more # consistent with frequency of severe infection reported in # https://www.nejm.org/doi/full/10.1056/NEJMoa2002032 (at a lower level of age granularity). p_mild_severe_cdc = np.zeros(N_AGES) p_mild_severe_cdc[0:20] = 0.016 p_mild_severe_cdc[20:45] = 0.143 p_mild_severe_cdc[45:55] = 0.212 p_mild_severe_cdc[55:65] = 0.205 p_mild_severe_cdc[65:75] = 0.286 p_mild_severe_cdc[75:85] = 0.305 p_mild_severe_cdc[85:] = 0.313 # overall probability of progression from critical to severe # https://www.ecdc.europa.eu/sites/default/files/documents/RRA-sixth-update-Outbreak-of-novel-coronavirus-disease-2019-COVID-19.pdf # taking midpoint of the intervals overall_p_severe_critical = (0.15 + 0.2) / 2 # overall mortality, which is set separately, but rather how many individuals # end up in critical state. 0.49 is from # http://weekly.chinacdc.cn/en/article/id/e53946e2-c6c4-41e9-9a9b-fea8db1a8f51 overall_p_critical_death = 0.49 # go back to using CDC hospitalization rates as mild->severe severe_critical_multiplier = overall_p_severe_critical / p_mild_severe_cdc critical_death_multiplier = overall_p_critical_death / p_mild_severe_cdc # get the overall CFR for each age/comorbidity combination by running the logistic model """ Mortality model. We fit a logistic regression to estimate p_mild_death from (age, diabetes, hypertension) to match the marginal mortality rates from TODO. The results of the logistic regression are used to set the disease severity transition probabilities. """ c_age = np.loadtxt(resource_filename(__package__, 'comorbidities/c_age.txt'), delimiter=',').mean(axis=0) """float vector: Logistic regression weights for each age bracket.""" c_diabetes = np.loadtxt(resource_filename(__package__, 'comorbidities/c_diabetes.txt'), delimiter=',').mean(axis=0) """float: Logistic regression weight for diabetes.""" c_hyper = np.loadtxt(resource_filename(__package__, 'comorbidities/c_hypertension.txt'), delimiter=',').mean(axis=0) """float: Logistic regression weight for hypertension.""" intervals = np.loadtxt(resource_filename( __package__, 'comorbidities/comorbidity_age_intervals.txt'), delimiter=',') def age_to_interval(i): """Return the corresponding comorbidity age interval for a specific age. Args: i (int): age. Returns: int: index of interval containing i in intervals. """ for idx, a in enumerate(intervals): if i >= a[0] and i < a[1]: return idx return idx p_death_target = np.zeros((N_AGES, 2, 2)) for i in range(N_AGES): for diabetes_state in [0, 1]: for hyper_state in [0, 1]: if i < intervals[0][0]: p_death_target[i, diabetes_state, hyper_state] = 0 else: p_death_target[i, diabetes_state, hyper_state] = sp.special.expit( c_age[age_to_interval(i)] + diabetes_state * c_diabetes + hyper_state * c_hyper) # p_death_target *= params['mortality_multiplier'] # p_death_target[p_death_target > 1] = 1 #calibrate the probability of the severe -> critical transition to match the #overall CFR for each age/comorbidity combination #age group, diabetes (0/1), hypertension (0/1) progression_rate = np.zeros((N_AGES, 2, 2)) p_mild_severe = np.zeros((N_AGES, 2, 2)) """float N_AGES x 2 x 2 vector: Probability a patient with a particular age combordity profile transitions from mild to severe state.""" p_severe_critical = np.zeros((N_AGES, 2, 2)) """float N_AGES x 2 x 2 vector: Probability a patient with a particular age combordity profile transitions from severe to critical state.""" p_critical_death = np.zeros((N_AGES, 2, 2)) """float N_AGES x 2 x 2 vector: Probability a patient with a particular age combordity profile transitions from critical to dead state.""" for i in range(N_AGES): for diabetes_state in [0, 1]: for hyper_state in [0, 1]: progression_rate[i, diabetes_state, hyper_state] = ( p_death_target[i, diabetes_state, hyper_state] / (severe_critical_multiplier[i] * critical_death_multiplier[i]))**(1. / 3) p_mild_severe[i, diabetes_state, hyper_state] = progression_rate[i, diabetes_state, hyper_state] p_severe_critical[i, diabetes_state, hyper_state] = severe_critical_multiplier[ i] * progression_rate[i, diabetes_state, hyper_state] p_critical_death[i, diabetes_state, hyper_state] = critical_death_multiplier[ i] * progression_rate[i, diabetes_state, hyper_state] #no critical cases under 20 (CDC) p_critical_death[:20] = 0 p_severe_critical[:20] = 0 #for now, just cap 80+yos with diabetes and hypertension p_critical_death[p_critical_death > 1] = 1 p_mild_severe *= mortality_multiplier**(1 / 3) p_severe_critical *= mortality_multiplier**(1 / 3) p_critical_death *= mortality_multiplier**(1 / 3) p_mild_severe[p_mild_severe > 1] = 1 p_severe_critical[p_severe_critical > 1] = 1 p_critical_death[p_critical_death > 1] = 1 return aljpy.dotdict( p_mild_severe=p_mild_severe, p_severe_critical=p_severe_critical, p_critical_death=p_critical_death, )
# If lockdown, by how much do divide contact matrix? LOCKDOWN_FACTOR = 2. # How infectious are asymptomatic cases relative to symptomatic ones # https://science.sciencemag.org/content/early/2020/03/13/science.abb3221 ASYMPTOMATIC_TRANSMISSIBILITY = 0.55 # DON'T CHANGE: we don't want p infect household to recalibrate for different policy what ifs on mean time to isolate MEAN_TIME_TO_ISOLATE = 4.6 # DON'T CHANGE TUNED = aljpy.dotdict(Italy=aljpy.dotdict( # increase probability of death for all ages and comorbidities by this amount mortality_multiplier=4, # Probability of infection given contact between two individuals # This is currently set arbitrarily and will be calibrated to match the empirical r0 pigc=.029, population=int(1e4), n_infected_start=5., start_date=date(2020, 1, 22), stay_home_date=date(2020, 3, 8), lockdown_date=date(2022, 12, 31))) # no lockdown AGE_GROUPS = { 'infected_1': '0-4', 'contact_1': '0-4', 'infected_2': '5-9', 'contact_2': '5-9', 'infected_3': '10-14', 'contact_3': '10-14', 'infected_4': '15-19', 'contact_4': '15-19',