-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
update parameters to enable interventions: a simpler and more reader-friendly way #1081
Merged
tbhallett
merged 2 commits into
master
from
EvaJ/contraception_improvement/better_implementation_of_intervs
Feb 11, 2024
Merged
update parameters to enable interventions: a simpler and more reader-friendly way #1081
tbhallett
merged 2 commits into
master
from
EvaJ/contraception_improvement/better_implementation_of_intervs
Feb 11, 2024
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@EvaJanouskova -- we have a conflict on this one, I see. Please could you resolve? |
ce5795d
to
db4fa21
Compare
@tbhallett , I rebased the branch on master, it should help. |
db4fa21
to
0f5d63b
Compare
@EvaJanouskova -- the changes per se here look great. But there is a conflict to resolve before we can we merge. Please could you sort out the conflict? Thanks |
0f5d63b
to
8b735a2
Compare
diff --git src/tlo/methods/contraception.py src/tlo/methods/contraception.py index aa1efa250..c3e8f9f77 100644 --- src/tlo/methods/contraception.py +++ src/tlo/methods/contraception.py @@ -596,122 +596,37 @@ class Contraception(Module): processed_params = self.processed_params - def expand_to_age_years(values_by_age_groups, ages_by_year): - _d = dict(zip(['15-19', '20-24', '25-29', '30-34', '35-39', '40-44', '45-49'], values_by_age_groups)) - return np.array( - [_d[self.sim.modules['Demography'].AGE_RANGE_LOOKUP[_age_year]] for _age_year in ages_by_year] - ) + def contraception_initiation_with_interv(p_start_per_month_without_interv): + """Increase the probabilities of a woman starting modern contraceptives due to Pop intervention being + applied.""" + # TODO: remove the keys before intervention year + p_start_per_month_with_interv = {} + for year, age_method_df in p_start_per_month_without_interv.items(): + p_start_per_month_with_interv[year] = age_method_df * self.parameters['Interventions_Pop'].loc[0] + return p_start_per_month_with_interv - def time_age_trend_in_initiation(): - """The age-specific effect of calendar year on the probability of starting use of contraceptive - (multiplicative effect). Values are chosen to induce a trend in age-specific fertility consistent with - the WPP estimates.""" + def contraception_initiation_after_birth_with_interv(p_start_after_birth_without_interv): + """Increase the probabilities of a woman starting modern contraceptives following giving birth due to PPFP + intervention being applied.""" + # Exclude prob of 'not_using' + p_start_after_birth_with_interv = p_start_after_birth_without_interv.copy().drop('not_using') - _years = np.arange(2010, 2101) - _ages = np.arange(15, 50) + # Apply PPFP intervention multipliers (ie increase probs of modern methods) + p_start_after_birth_with_interv = \ + p_start_after_birth_with_interv.mul(self.parameters['Interventions_PPFP'].loc[0]) - _init_over_time = np.exp(+0.05 * np.minimum(2020 - 2010, (_years - 2010))) * np.maximum(1.0, np.exp( - +0.01 * (_years - 2020))) - _init_over_time_modification_by_age = 1.0 / expand_to_age_years([1.0, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5], _ages) - _init = np.outer(_init_over_time, _init_over_time_modification_by_age) + # Return reduced prob of 'not_using' + p_start_after_birth_with_interv = pd.Series((1.0 - p_start_after_birth_with_interv.sum()), + index=['not_using']).append(p_start_after_birth_with_interv) - return pd.DataFrame(index=_years, columns=_ages, data=_init) + return p_start_after_birth_with_interv - def avoid_sterilization_below30(probs): - """Prevent women below 30 years having female sterilization and adjust the probability for women 30 and over - to preserve the overall probability of initiating sterilization.""" - # Input 'probs' must include probs for all methods including 'not_using' - assert set(probs.index) == set(self.all_contraception_states) - - # Prevent women below 30 years having 'female_sterilization' - probs_below30 = probs.copy() - probs_below30['female_sterilization'] = 0.0 - # Scale so that the probability of all outcomes sum to 1.0 - probs_below30 = probs_below30 / probs_below30.sum() - assert np.isclose(1.0, probs_below30.sum()) - - # Increase prob of 'female_sterilization' in older women accordingly - probs_30plus = probs.copy() - probs_30plus['female_sterilization'] = ( - probs.loc['female_sterilization'] / - self.ratio_n_females_30_49_to_15_49_in_2010 - ) - # Scale so that the probability of all outcomes sum to 1.0 - probs_30plus = probs_30plus / probs_30plus.sum() - assert np.isclose(1.0, probs_30plus.sum()) - - return probs_below30, probs_30plus - - def contraception_initiation_with_interv(): - """Generate the probability per month of a woman initiating onto each contraceptive, by the age (in whole - years) if FP interventions are applied.""" - - # Probability of initiation by method per month (average over all ages) - p_init_by_method = self.parameters['Initiation_ByMethod'].loc[0] - - # Prevent women below 30 years having 'female_sterilization' while preserving the overall probability of - # 'female_sterilization' initiation - p_init_by_method_below30, p_init_by_method_30plus = avoid_sterilization_below30(p_init_by_method) - - # Effect of age - age_effect = 1.0 + self.parameters['Initiation_ByAge'].set_index('age')['r_init1_age'].rename_axis( - "age_years") - - # Year effect - year_effect = time_age_trend_in_initiation() - - def apply_intervention_age_year_effects(probs_below30, probs_30plus): - # Apply Pop intervention - probs_by_method_below30 = \ - probs_below30.copy().drop('not_using').mul(self.parameters['Interventions_Pop'].loc[0]) - probs_by_method_30plus = \ - probs_30plus.copy().drop('not_using').mul(self.parameters['Interventions_Pop'].loc[0]) - # Assemble into age-specific data-frame: - p_init = dict() - for year in year_effect.index: - - p_init_this_year = dict() - for a in age_effect.index: - if a < 30: - p_init_this_year[a] = probs_by_method_below30 * age_effect.at[a] * year_effect.at[year, a] - else: - p_init_this_year[a] = probs_by_method_30plus * age_effect.at[a] * year_effect.at[year, a] - p_init_this_year_df = pd.DataFrame.from_dict(p_init_this_year, orient='index') - - # Check correct format of age/method data-frame - assert set(p_init_this_year_df.columns) == set(self.all_contraception_states - {'not_using'}) - assert (p_init_this_year_df.index == range(15, 50)).all() - assert (p_init_this_year_df >= 0.0).all().all() - - p_init[year] = p_init_this_year_df - - return p_init - - return apply_intervention_age_year_effects(p_init_by_method_below30, p_init_by_method_30plus) - - def contraception_initiation_after_birth_with_interv(): - """Get the probability of a woman starting a contraceptive following giving birth if FP interventions are - applied. Avoid sterilization in women below 30 years old.""" - - # Get initiation probabilities of contraception methods after birth from read-in Excel sheet - p_start_after_birth = self.parameters['Initiation_AfterBirth'].loc[0].drop('not_using') - - # Apply PPFP intervention multipliers - p_start_after_birth = p_start_after_birth.mul(self.parameters['Interventions_PPFP'].loc[0]) - - # Add 'not_using' to initiation probabilities of contraception methods after birth - p_start_after_birth = pd.concat( - ( - pd.Series((1.0 - p_start_after_birth.sum()), index=['not_using']), - p_start_after_birth - ) - ) - - return avoid_sterilization_below30(p_start_after_birth) - - processed_params['p_start_per_month'] = contraception_initiation_with_interv() - processed_params['p_start_after_birth_below30'], processed_params['p_start_after_birth_30plus'] =\ - contraception_initiation_after_birth_with_interv() + processed_params['p_start_per_month'] = \ + contraception_initiation_with_interv(processed_params['p_start_per_month']) + processed_params['p_start_after_birth_below30'] = \ + contraception_initiation_after_birth_with_interv(processed_params['p_start_after_birth_below30']) + processed_params['p_start_after_birth_30plus'] = \ + contraception_initiation_after_birth_with_interv(processed_params['p_start_after_birth_30plus']) return processed_params
8b735a2
to
84d9b16
Compare
tbhallett
approved these changes
Feb 11, 2024
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
update_params_for_interventions()
fnc is re-written so that all the calculations are not done again and among those calculations multiplied by the interventions multipliers, instead the final probs without interventions are multiplied by those multipliers.The initiation probs 'p_stop_per_month' with intervention calculated with the old version versus new version of
contraception_initiation_with_interv
are the same if up to 16 decimals are considered.(I have also removed the calculations for the years before the interventions started, as they are not needed at that time.)
The initiation probs after birth 'p_start_after_birth_below30' and 'p_start_after_birth_30plus' calculated with the old version versus new version of
contraception_initiation_after_birth_with_interv
are the same if up to 5 decimals are considered.