예제 #1
0
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,
    )
예제 #2
0
# 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',