vivarium-public-health 4.3.2__py3-none-any.whl → 4.3.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vivarium_public_health/__init__.py +1 -7
- vivarium_public_health/_version.py +1 -1
- vivarium_public_health/population/data_transformations.py +13 -14
- vivarium_public_health/results/__init__.py +0 -1
- vivarium_public_health/risks/base_risk.py +214 -34
- vivarium_public_health/risks/data_transformations.py +245 -23
- vivarium_public_health/risks/distributions.py +484 -17
- vivarium_public_health/risks/effect.py +320 -34
- vivarium_public_health/risks/implementations/low_birth_weight_and_short_gestation.py +12 -17
- vivarium_public_health/treatment/__init__.py +0 -1
- {vivarium_public_health-4.3.2.dist-info → vivarium_public_health-4.3.4.dist-info}/METADATA +2 -2
- {vivarium_public_health-4.3.2.dist-info → vivarium_public_health-4.3.4.dist-info}/RECORD +15 -22
- vivarium_public_health/exposure/__init__.py +0 -2
- vivarium_public_health/exposure/data_transformations.py +0 -254
- vivarium_public_health/exposure/distributions.py +0 -555
- vivarium_public_health/exposure/effect.py +0 -356
- vivarium_public_health/exposure/exposure.py +0 -254
- vivarium_public_health/results/intervention.py +0 -139
- vivarium_public_health/treatment/intervention.py +0 -85
- {vivarium_public_health-4.3.2.dist-info → vivarium_public_health-4.3.4.dist-info}/WHEEL +0 -0
- {vivarium_public_health-4.3.2.dist-info → vivarium_public_health-4.3.4.dist-info}/licenses/LICENSE.txt +0 -0
- {vivarium_public_health-4.3.2.dist-info → vivarium_public_health-4.3.4.dist-info}/top_level.txt +0 -0
@@ -3,50 +3,338 @@
|
|
3
3
|
Risk Effect Models
|
4
4
|
==================
|
5
5
|
|
6
|
-
|
6
|
+
This module contains tools for modeling the relationship between risk
|
7
|
+
exposure models and disease models.
|
7
8
|
|
8
|
-
|
9
|
+
"""
|
9
10
|
from collections.abc import Callable
|
11
|
+
from importlib import import_module
|
10
12
|
from typing import Any
|
11
13
|
|
12
14
|
import numpy as np
|
13
15
|
import pandas as pd
|
14
16
|
import scipy
|
17
|
+
from layered_config_tree import ConfigurationError
|
18
|
+
from vivarium import Component
|
15
19
|
from vivarium.framework.engine import Builder
|
20
|
+
from vivarium.framework.values import Pipeline
|
16
21
|
|
17
|
-
from vivarium_public_health.
|
18
|
-
from vivarium_public_health.
|
19
|
-
|
22
|
+
from vivarium_public_health.risks import Risk
|
23
|
+
from vivarium_public_health.risks.data_transformations import (
|
24
|
+
load_exposure_data,
|
25
|
+
pivot_categorical,
|
26
|
+
)
|
27
|
+
from vivarium_public_health.risks.distributions import MissingDataError
|
28
|
+
from vivarium_public_health.utilities import EntityString, TargetString, get_lookup_columns
|
20
29
|
|
21
30
|
|
22
|
-
class RiskEffect(
|
31
|
+
class RiskEffect(Component):
|
23
32
|
"""A component to model the effect of a risk factor on an affected entity's target rate.
|
24
33
|
|
25
34
|
This component can source data either from builder.data or from parameters
|
26
35
|
supplied in the configuration.
|
27
36
|
|
37
|
+
For a risk named 'risk' that affects 'affected_risk' and 'affected_cause',
|
38
|
+
the configuration would look like:
|
39
|
+
|
40
|
+
.. code-block:: yaml
|
41
|
+
|
42
|
+
configuration:
|
43
|
+
risk_effect.risk_name_on_affected_target:
|
44
|
+
exposure_parameters: 2
|
45
|
+
incidence_rate: 10
|
46
|
+
|
28
47
|
"""
|
29
48
|
|
49
|
+
###############
|
50
|
+
# Properties #
|
51
|
+
##############
|
52
|
+
|
53
|
+
@property
|
54
|
+
def name(self) -> str:
|
55
|
+
return self.get_name(self.risk, self.target)
|
56
|
+
|
57
|
+
@staticmethod
|
58
|
+
def get_name(risk: EntityString, target: TargetString) -> str:
|
59
|
+
return f"risk_effect.{risk.name}_on_{target}"
|
60
|
+
|
61
|
+
@property
|
62
|
+
def configuration_defaults(self) -> dict[str, Any]:
|
63
|
+
"""Default values for any configurations managed by this component."""
|
64
|
+
return {
|
65
|
+
self.name: {
|
66
|
+
"data_sources": {
|
67
|
+
"relative_risk": f"{self.risk}.relative_risk",
|
68
|
+
"population_attributable_fraction": f"{self.risk}.population_attributable_fraction",
|
69
|
+
},
|
70
|
+
"data_source_parameters": {
|
71
|
+
"relative_risk": {},
|
72
|
+
},
|
73
|
+
}
|
74
|
+
}
|
75
|
+
|
30
76
|
@property
|
31
|
-
def
|
32
|
-
|
33
|
-
"
|
34
|
-
|
35
|
-
|
77
|
+
def is_exposure_categorical(self) -> bool:
|
78
|
+
return self._exposure_distribution_type in [
|
79
|
+
"dichotomous",
|
80
|
+
"ordered_polytomous",
|
81
|
+
"unordered_polytomous",
|
82
|
+
]
|
83
|
+
|
84
|
+
#####################
|
85
|
+
# Lifecycle methods #
|
86
|
+
#####################
|
87
|
+
|
88
|
+
def __init__(self, risk: str, target: str):
|
89
|
+
"""
|
90
|
+
|
91
|
+
Parameters
|
92
|
+
----------
|
93
|
+
risk
|
94
|
+
Type and name of risk factor, supplied in the form
|
95
|
+
"risk_type.risk_name" where risk_type should be singular (e.g.,
|
96
|
+
risk_factor instead of risk_factors).
|
97
|
+
target
|
98
|
+
Type, name, and target rate of entity to be affected by risk factor,
|
99
|
+
supplied in the form "entity_type.entity_name.measure"
|
100
|
+
where entity_type should be singular (e.g., cause instead of causes).
|
101
|
+
"""
|
102
|
+
super().__init__()
|
103
|
+
self.risk = EntityString(risk)
|
104
|
+
self.target = TargetString(target)
|
105
|
+
|
106
|
+
self._exposure_distribution_type = None
|
107
|
+
|
108
|
+
self.exposure_pipeline_name = f"{self.risk.name}.exposure"
|
109
|
+
self.target_pipeline_name = f"{self.target.name}.{self.target.measure}"
|
110
|
+
self.target_paf_pipeline_name = f"{self.target_pipeline_name}.paf"
|
111
|
+
|
112
|
+
# noinspection PyAttributeOutsideInit
|
113
|
+
def setup(self, builder: Builder) -> None:
|
114
|
+
self.exposure = self.get_risk_exposure(builder)
|
115
|
+
|
116
|
+
self._relative_risk_source = self.get_relative_risk_source(builder)
|
117
|
+
self.relative_risk = self.get_relative_risk_pipeline(builder)
|
118
|
+
|
119
|
+
self.register_target_modifier(builder)
|
120
|
+
self.register_paf_modifier(builder)
|
121
|
+
|
122
|
+
#################
|
123
|
+
# Setup methods #
|
124
|
+
#################
|
125
|
+
|
126
|
+
def build_all_lookup_tables(self, builder: Builder) -> None:
|
127
|
+
self._exposure_distribution_type = self.get_distribution_type(builder)
|
128
|
+
|
129
|
+
rr_data = self.load_relative_risk(builder)
|
130
|
+
rr_value_cols = None
|
131
|
+
if self.is_exposure_categorical:
|
132
|
+
rr_data, rr_value_cols = self.process_categorical_data(builder, rr_data)
|
133
|
+
self.lookup_tables["relative_risk"] = self.build_lookup_table(
|
134
|
+
builder, rr_data, rr_value_cols
|
135
|
+
)
|
136
|
+
|
137
|
+
paf_data = self.get_filtered_data(
|
138
|
+
builder, self.configuration.data_sources.population_attributable_fraction
|
36
139
|
)
|
37
|
-
|
38
|
-
|
39
|
-
@risk.setter
|
40
|
-
def risk(self, value: str) -> None:
|
41
|
-
warnings.warn(
|
42
|
-
"The 'risk' attribute is deprecated. Use 'entity' instead.",
|
43
|
-
DeprecationWarning,
|
44
|
-
stacklevel=2,
|
140
|
+
self.lookup_tables["population_attributable_fraction"] = self.build_lookup_table(
|
141
|
+
builder, paf_data
|
45
142
|
)
|
46
|
-
self.entity = value
|
47
143
|
|
48
|
-
def
|
49
|
-
|
144
|
+
def get_distribution_type(self, builder: Builder) -> str:
|
145
|
+
"""Get the distribution type for the risk from the configuration."""
|
146
|
+
risk_exposure_component = self._get_risk_exposure_class(builder)
|
147
|
+
if risk_exposure_component.distribution_type:
|
148
|
+
return risk_exposure_component.distribution_type
|
149
|
+
return risk_exposure_component.get_distribution_type(builder)
|
150
|
+
|
151
|
+
def load_relative_risk(
|
152
|
+
self,
|
153
|
+
builder: Builder,
|
154
|
+
configuration=None,
|
155
|
+
) -> str | float | pd.DataFrame:
|
156
|
+
if configuration is None:
|
157
|
+
configuration = self.configuration
|
158
|
+
|
159
|
+
rr_source = configuration.data_sources.relative_risk
|
160
|
+
rr_dist_parameters = configuration.data_source_parameters.relative_risk.to_dict()
|
161
|
+
|
162
|
+
if isinstance(rr_source, str):
|
163
|
+
try:
|
164
|
+
distribution = getattr(import_module("scipy.stats"), rr_source)
|
165
|
+
rng = np.random.default_rng(builder.randomness.get_seed(self.name))
|
166
|
+
rr_data = distribution(**rr_dist_parameters).ppf(rng.random())
|
167
|
+
except AttributeError:
|
168
|
+
rr_data = self.get_filtered_data(builder, rr_source)
|
169
|
+
except TypeError:
|
170
|
+
raise ConfigurationError(
|
171
|
+
f"Parameters {rr_dist_parameters} are not valid for distribution {rr_source}."
|
172
|
+
)
|
173
|
+
else:
|
174
|
+
rr_data = self.get_filtered_data(builder, rr_source)
|
175
|
+
return rr_data
|
176
|
+
|
177
|
+
def get_filtered_data(
|
178
|
+
self, builder: "Builder", data_source: str | float | pd.DataFrame
|
179
|
+
) -> float | pd.DataFrame:
|
180
|
+
data = super().get_data(builder, data_source)
|
181
|
+
|
182
|
+
if isinstance(data, pd.DataFrame):
|
183
|
+
# filter data to only include the target entity and measure
|
184
|
+
correct_target_mask = True
|
185
|
+
columns_to_drop = []
|
186
|
+
if "affected_entity" in data.columns:
|
187
|
+
correct_target_mask &= data["affected_entity"] == self.target.name
|
188
|
+
columns_to_drop.append("affected_entity")
|
189
|
+
if "affected_measure" in data.columns:
|
190
|
+
correct_target_mask &= data["affected_measure"] == self.target.measure
|
191
|
+
columns_to_drop.append("affected_measure")
|
192
|
+
data = data[correct_target_mask].drop(columns=columns_to_drop)
|
193
|
+
return data
|
194
|
+
|
195
|
+
def process_categorical_data(
|
196
|
+
self, builder: Builder, rr_data: str | float | pd.DataFrame
|
197
|
+
) -> tuple[str | float | pd.DataFrame, list[str]]:
|
198
|
+
if not isinstance(rr_data, pd.DataFrame):
|
199
|
+
cat1 = builder.data.load("population.demographic_dimensions")
|
200
|
+
cat1["parameter"] = "cat1"
|
201
|
+
cat1["value"] = rr_data
|
202
|
+
cat2 = cat1.copy()
|
203
|
+
cat2["parameter"] = "cat2"
|
204
|
+
cat2["value"] = 1
|
205
|
+
rr_data = pd.concat([cat1, cat2], ignore_index=True)
|
206
|
+
if "parameter" in rr_data.index.names:
|
207
|
+
rr_data = rr_data.reset_index("parameter")
|
208
|
+
|
209
|
+
rr_value_cols = list(rr_data["parameter"].unique())
|
210
|
+
rr_data = pivot_categorical(builder, self.risk, rr_data, "parameter")
|
211
|
+
return rr_data, rr_value_cols
|
212
|
+
|
213
|
+
# todo currently this isn't being called. we need to properly set rrs if
|
214
|
+
# the exposure has been rebinned
|
215
|
+
def rebin_relative_risk_data(
|
216
|
+
self, builder, relative_risk_data: pd.DataFrame
|
217
|
+
) -> pd.DataFrame:
|
218
|
+
"""Rebin relative risk data.
|
219
|
+
|
220
|
+
When the polytomous risk is rebinned, matching relative risk needs to be rebinned.
|
221
|
+
After rebinning, rr for both exposed and unexposed categories should be the weighted sum of relative risk
|
222
|
+
of the component categories where weights are relative proportions of exposure of those categories.
|
223
|
+
For example, if cat1, cat2, cat3 are exposed categories and cat4 is unexposed with exposure [0.1,0.2,0.3,0.4],
|
224
|
+
for the matching rr = [rr1, rr2, rr3, 1], rebinned rr for the rebinned cat1 should be:
|
225
|
+
(0.1 *rr1 + 0.2 * rr2 + 0.3* rr3) / (0.1+0.2+0.3)
|
226
|
+
"""
|
227
|
+
if not self.risk in builder.configuration.to_dict():
|
228
|
+
return relative_risk_data
|
229
|
+
|
230
|
+
rebin_exposed_categories = set(builder.configuration[self.risk]["rebinned_exposed"])
|
231
|
+
|
232
|
+
if rebin_exposed_categories:
|
233
|
+
# todo make sure this works
|
234
|
+
exposure_data = load_exposure_data(builder, self.risk)
|
235
|
+
relative_risk_data = self._rebin_relative_risk_data(
|
236
|
+
relative_risk_data, exposure_data, rebin_exposed_categories
|
237
|
+
)
|
238
|
+
|
239
|
+
return relative_risk_data
|
240
|
+
|
241
|
+
def _rebin_relative_risk_data(
|
242
|
+
self,
|
243
|
+
relative_risk_data: pd.DataFrame,
|
244
|
+
exposure_data: pd.DataFrame,
|
245
|
+
rebin_exposed_categories: set,
|
246
|
+
) -> pd.DataFrame:
|
247
|
+
cols = list(exposure_data.columns.difference(["value"]))
|
248
|
+
|
249
|
+
relative_risk_data = relative_risk_data.merge(exposure_data, on=cols)
|
250
|
+
relative_risk_data["value_x"] = relative_risk_data.value_x.multiply(
|
251
|
+
relative_risk_data.value_y
|
252
|
+
)
|
253
|
+
relative_risk_data.parameter = relative_risk_data["parameter"].map(
|
254
|
+
lambda p: "cat1" if p in rebin_exposed_categories else "cat2"
|
255
|
+
)
|
256
|
+
relative_risk_data = relative_risk_data.groupby(cols).sum().reset_index()
|
257
|
+
relative_risk_data["value"] = relative_risk_data.value_x.divide(
|
258
|
+
relative_risk_data.value_y
|
259
|
+
).fillna(0)
|
260
|
+
return relative_risk_data.drop(columns=["value_x", "value_y"])
|
261
|
+
|
262
|
+
def get_risk_exposure(self, builder: Builder) -> Callable[[pd.Index], pd.Series]:
|
263
|
+
return builder.value.get_value(self.exposure_pipeline_name)
|
264
|
+
|
265
|
+
def adjust_target(self, index: pd.Index, target: pd.Series) -> pd.Series:
|
266
|
+
relative_risk = self.relative_risk(index)
|
267
|
+
return target * relative_risk
|
268
|
+
|
269
|
+
def get_relative_risk_source(self, builder: Builder) -> Callable[[pd.Index], pd.Series]:
|
270
|
+
|
271
|
+
if not self.is_exposure_categorical:
|
272
|
+
tmred = builder.data.load(f"{self.risk}.tmred")
|
273
|
+
tmrel = 0.5 * (tmred["min"] + tmred["max"])
|
274
|
+
scale = builder.data.load(f"{self.risk}.relative_risk_scalar")
|
275
|
+
|
276
|
+
def generate_relative_risk(index: pd.Index) -> pd.Series:
|
277
|
+
rr = self.lookup_tables["relative_risk"](index)
|
278
|
+
exposure = self.exposure(index)
|
279
|
+
relative_risk = np.maximum(rr.values ** ((exposure - tmrel) / scale), 1)
|
280
|
+
return relative_risk
|
281
|
+
|
282
|
+
else:
|
283
|
+
index_columns = ["index", self.risk.name]
|
284
|
+
|
285
|
+
def generate_relative_risk(index: pd.Index) -> pd.Series:
|
286
|
+
rr = self.lookup_tables["relative_risk"](index)
|
287
|
+
exposure = self.exposure(index).reset_index()
|
288
|
+
exposure.columns = index_columns
|
289
|
+
exposure = exposure.set_index(index_columns)
|
290
|
+
|
291
|
+
relative_risk = rr.stack().reset_index()
|
292
|
+
relative_risk.columns = index_columns + ["value"]
|
293
|
+
relative_risk = relative_risk.set_index(index_columns)
|
294
|
+
|
295
|
+
effect = relative_risk.loc[exposure.index, "value"].droplevel(self.risk.name)
|
296
|
+
return effect
|
297
|
+
|
298
|
+
return generate_relative_risk
|
299
|
+
|
300
|
+
def get_relative_risk_pipeline(self, builder: Builder) -> Pipeline:
|
301
|
+
return builder.value.register_value_producer(
|
302
|
+
f"{self.risk.name}_on_{self.target.name}.relative_risk",
|
303
|
+
self._relative_risk_source,
|
304
|
+
component=self,
|
305
|
+
required_resources=[self.exposure],
|
306
|
+
)
|
307
|
+
|
308
|
+
def register_target_modifier(self, builder: Builder) -> None:
|
309
|
+
builder.value.register_value_modifier(
|
310
|
+
self.target_pipeline_name,
|
311
|
+
modifier=self.adjust_target,
|
312
|
+
component=self,
|
313
|
+
required_resources=[self.relative_risk],
|
314
|
+
)
|
315
|
+
|
316
|
+
def register_paf_modifier(self, builder: Builder) -> None:
|
317
|
+
required_columns = get_lookup_columns(
|
318
|
+
[self.lookup_tables["population_attributable_fraction"]]
|
319
|
+
)
|
320
|
+
builder.value.register_value_modifier(
|
321
|
+
self.target_paf_pipeline_name,
|
322
|
+
modifier=self.lookup_tables["population_attributable_fraction"],
|
323
|
+
component=self,
|
324
|
+
required_resources=required_columns,
|
325
|
+
)
|
326
|
+
|
327
|
+
##################
|
328
|
+
# Helper methods #
|
329
|
+
##################
|
330
|
+
|
331
|
+
def _get_risk_exposure_class(self, builder: Builder) -> Risk:
|
332
|
+
risk_exposure_component = builder.components.get_component(self.risk)
|
333
|
+
if not isinstance(risk_exposure_component, Risk):
|
334
|
+
raise ValueError(
|
335
|
+
f"Risk effect model {self.name} requires a Risk component named {self.risk}"
|
336
|
+
)
|
337
|
+
return risk_exposure_component
|
50
338
|
|
51
339
|
|
52
340
|
class NonLogLinearRiskEffect(RiskEffect):
|
@@ -78,15 +366,15 @@ class NonLogLinearRiskEffect(RiskEffect):
|
|
78
366
|
return {
|
79
367
|
self.name: {
|
80
368
|
"data_sources": {
|
81
|
-
"relative_risk": f"{self.
|
82
|
-
"population_attributable_fraction": f"{self.
|
369
|
+
"relative_risk": f"{self.risk}.relative_risk",
|
370
|
+
"population_attributable_fraction": f"{self.risk}.population_attributable_fraction",
|
83
371
|
},
|
84
372
|
}
|
85
373
|
}
|
86
374
|
|
87
375
|
@property
|
88
376
|
def columns_required(self) -> list[str]:
|
89
|
-
return [f"{self.
|
377
|
+
return [f"{self.risk.name}_exposure"]
|
90
378
|
|
91
379
|
#################
|
92
380
|
# Setup methods #
|
@@ -126,8 +414,8 @@ class NonLogLinearRiskEffect(RiskEffect):
|
|
126
414
|
.reset_index()
|
127
415
|
)
|
128
416
|
rr_data = rr_data.drop("parameter", axis=1)
|
129
|
-
rr_data[f"{self.
|
130
|
-
rr_data[f"{self.
|
417
|
+
rr_data[f"{self.risk.name}_exposure_start"] = rr_data["left_exposure"]
|
418
|
+
rr_data[f"{self.risk.name}_exposure_end"] = rr_data["right_exposure"]
|
131
419
|
# build lookup table
|
132
420
|
rr_value_cols = ["left_exposure", "left_rr", "right_exposure", "right_rr"]
|
133
421
|
self.lookup_tables["relative_risk"] = self.build_lookup_table(
|
@@ -150,19 +438,17 @@ class NonLogLinearRiskEffect(RiskEffect):
|
|
150
438
|
configuration = self.configuration
|
151
439
|
|
152
440
|
# get TMREL
|
153
|
-
tmred = builder.data.load(f"{self.
|
441
|
+
tmred = builder.data.load(f"{self.risk}.tmred")
|
154
442
|
if tmred["distribution"] == "uniform":
|
155
443
|
draw = builder.configuration.input_data.input_draw_number
|
156
444
|
rng = np.random.default_rng(builder.randomness.get_seed(self.name + str(draw)))
|
157
445
|
self.tmrel = rng.uniform(tmred["min"], tmred["max"])
|
158
446
|
elif tmred["distribution"] == "draws": # currently only for iron deficiency
|
159
447
|
raise MissingDataError(
|
160
|
-
f"This data has draw-level TMRELs. You will need to contact the research team that models {self.
|
448
|
+
f"This data has draw-level TMRELs. You will need to contact the research team that models {self.risk.name} to get this data."
|
161
449
|
)
|
162
450
|
else:
|
163
|
-
raise MissingDataError(
|
164
|
-
f"No TMRED found in gbd_mapping for risk {self.entity.name}"
|
165
|
-
)
|
451
|
+
raise MissingDataError(f"No TMRED found in gbd_mapping for risk {self.risk.name}")
|
166
452
|
|
167
453
|
# calculate RR at TMREL
|
168
454
|
rr_source = configuration.data_sources.relative_risk
|
@@ -203,7 +489,7 @@ class NonLogLinearRiskEffect(RiskEffect):
|
|
203
489
|
def get_relative_risk_source(self, builder: Builder) -> Callable[[pd.Index], pd.Series]:
|
204
490
|
def generate_relative_risk(index: pd.Index) -> pd.Series:
|
205
491
|
rr_intervals = self.lookup_tables["relative_risk"](index)
|
206
|
-
exposure = self.population_view.get(index)[f"{self.
|
492
|
+
exposure = self.population_view.get(index)[f"{self.risk.name}_exposure"]
|
207
493
|
x1, x2 = (
|
208
494
|
rr_intervals["left_exposure"].values,
|
209
495
|
rr_intervals["right_exposure"].values,
|
@@ -226,7 +512,7 @@ class NonLogLinearRiskEffect(RiskEffect):
|
|
226
512
|
parameter_data_is_numeric = rr_data["parameter"].dtype.kind in "biufc"
|
227
513
|
if not parameter_data_is_numeric:
|
228
514
|
raise ValueError(
|
229
|
-
f"The parameter column in your {self.
|
515
|
+
f"The parameter column in your {self.risk.name} relative risk data must contain numeric data. Its dtype is {rr_data['parameter'].dtype} instead."
|
230
516
|
)
|
231
517
|
|
232
518
|
# and that these RR values are monotonically increasing within each demographic group
|
@@ -22,12 +22,12 @@ from vivarium.framework.population import SimulantData
|
|
22
22
|
from vivarium.framework.resource import Resource
|
23
23
|
from vivarium.framework.values import Pipeline
|
24
24
|
|
25
|
-
from vivarium_public_health.exposure.distributions import PolytomousDistribution
|
26
25
|
from vivarium_public_health.risks import Risk, RiskEffect
|
27
26
|
from vivarium_public_health.risks.data_transformations import (
|
28
27
|
get_exposure_post_processor,
|
29
28
|
pivot_categorical,
|
30
29
|
)
|
30
|
+
from vivarium_public_health.risks.distributions import PolytomousDistribution
|
31
31
|
from vivarium_public_health.utilities import EntityString, get_lookup_columns, to_snake_case
|
32
32
|
|
33
33
|
CATEGORICAL = "categorical"
|
@@ -71,10 +71,7 @@ class LBWSGDistribution(PolytomousDistribution):
|
|
71
71
|
|
72
72
|
if isinstance(birth_exposure_data, pd.DataFrame):
|
73
73
|
birth_exposure_data = pivot_categorical(
|
74
|
-
builder,
|
75
|
-
self.exposure_component.entity,
|
76
|
-
birth_exposure_data,
|
77
|
-
"parameter",
|
74
|
+
builder, self.risk, birth_exposure_data, "parameter"
|
78
75
|
)
|
79
76
|
|
80
77
|
self.lookup_tables["birth_exposure"] = self.build_lookup_table(
|
@@ -121,9 +118,7 @@ class LBWSGDistribution(PolytomousDistribution):
|
|
121
118
|
-------
|
122
119
|
The intervals for each category.
|
123
120
|
"""
|
124
|
-
categories: dict[str, str] = builder.data.load(
|
125
|
-
f"{self.exposure_component.entity}.categories"
|
126
|
-
)
|
121
|
+
categories: dict[str, str] = builder.data.load(f"{self.risk}.categories")
|
127
122
|
category_intervals = {
|
128
123
|
axis: {
|
129
124
|
category: self._parse_description(axis, description)
|
@@ -276,7 +271,7 @@ class LBWSGRisk(Risk):
|
|
276
271
|
# Add birth exposure data source
|
277
272
|
configuration_defaults[self.name]["data_sources"][
|
278
273
|
"birth_exposure"
|
279
|
-
] = f"{self.
|
274
|
+
] = f"{self.risk}.birth_exposure"
|
280
275
|
configuration_defaults[self.name]["distribution_type"] = "lbwsg"
|
281
276
|
return configuration_defaults
|
282
277
|
|
@@ -305,7 +300,7 @@ class LBWSGRisk(Risk):
|
|
305
300
|
# Propensity only used on initialization; not being saved to avoid a cycle
|
306
301
|
return None
|
307
302
|
|
308
|
-
def
|
303
|
+
def get_exposure_pipeline(self, builder: Builder) -> Pipeline | None:
|
309
304
|
# Exposure only used on initialization; not being saved to avoid a cycle
|
310
305
|
return None
|
311
306
|
|
@@ -364,7 +359,7 @@ class LBWSGRisk(Risk):
|
|
364
359
|
|
365
360
|
def get_current_exposure(self, index: pd.Index) -> pd.DataFrame:
|
366
361
|
raise LifeCycleError(
|
367
|
-
f"The {self.
|
362
|
+
f"The {self.risk.name} exposure pipeline should not be called. You probably want to"
|
368
363
|
f" refer directly one of the exposure columns. During simulant initialization the birth"
|
369
364
|
f" exposure pipelines should be used instead."
|
370
365
|
)
|
@@ -405,12 +400,12 @@ class LBWSGRiskEffect(RiskEffect):
|
|
405
400
|
LBWSGRisk.get_exposure_column_name(axis) for axis in LBWSGRisk.AXES
|
406
401
|
]
|
407
402
|
self.relative_risk_pipeline_name = (
|
408
|
-
f"effect_of_{self.
|
403
|
+
f"effect_of_{self.risk.name}_on_{self.target.name}.relative_risk"
|
409
404
|
)
|
410
405
|
|
411
406
|
def relative_risk_column_name(self, age_group_id: str) -> str:
|
412
407
|
return (
|
413
|
-
f"effect_of_{self.
|
408
|
+
f"effect_of_{self.risk.name}_on_{age_group_id}_{self.target.name}_relative_risk"
|
414
409
|
)
|
415
410
|
|
416
411
|
# noinspection PyAttributeOutsideInit
|
@@ -431,7 +426,7 @@ class LBWSGRiskEffect(RiskEffect):
|
|
431
426
|
builder, paf_data, paf_value_cols
|
432
427
|
)
|
433
428
|
|
434
|
-
def
|
429
|
+
def get_risk_exposure(self, builder: Builder) -> Callable[[pd.Index], pd.DataFrame]:
|
435
430
|
def exposure(index: pd.Index) -> pd.DataFrame:
|
436
431
|
return self.population_view.subview(self.lbwsg_exposure_column_names).get(index)
|
437
432
|
|
@@ -440,7 +435,7 @@ class LBWSGRiskEffect(RiskEffect):
|
|
440
435
|
def get_population_attributable_fraction_source(
|
441
436
|
self, builder: Builder
|
442
437
|
) -> tuple[pd.DataFrame, list[str]]:
|
443
|
-
paf_key = f"{self.
|
438
|
+
paf_key = f"{self.risk}.population_attributable_fraction"
|
444
439
|
paf_data = builder.data.load(paf_key)
|
445
440
|
return paf_data, builder.data.value_columns()(paf_key)
|
446
441
|
|
@@ -454,7 +449,7 @@ class LBWSGRiskEffect(RiskEffect):
|
|
454
449
|
|
455
450
|
def get_age_intervals(self, builder: Builder) -> dict[str, pd.Interval]:
|
456
451
|
age_bins = builder.data.load("population.age_bins").set_index("age_start")
|
457
|
-
relative_risks = builder.data.load(f"{self.
|
452
|
+
relative_risks = builder.data.load(f"{self.risk}.relative_risk")
|
458
453
|
exposed_age_group_starts = (
|
459
454
|
relative_risks.groupby("age_start")["value"].any().reset_index()["age_start"]
|
460
455
|
)
|
@@ -481,7 +476,7 @@ class LBWSGRiskEffect(RiskEffect):
|
|
481
476
|
}
|
482
477
|
|
483
478
|
# get relative risk data for target
|
484
|
-
interpolators = builder.data.load(f"{self.
|
479
|
+
interpolators = builder.data.load(f"{self.risk}.relative_risk_interpolator")
|
485
480
|
interpolators = (
|
486
481
|
# isolate RRs for target and drop non-neonatal age groups since they have RR == 1.0
|
487
482
|
interpolators[
|
@@ -1,4 +1,3 @@
|
|
1
|
-
from vivarium_public_health.treatment.intervention import Intervention, InterventionEffect
|
2
1
|
from vivarium_public_health.treatment.magic_wand import AbsoluteShift
|
3
2
|
from vivarium_public_health.treatment.scale_up import LinearScaleUp
|
4
3
|
from vivarium_public_health.treatment.therapeutic_inertia import TherapeuticInertia
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: vivarium_public_health
|
3
|
-
Version: 4.3.
|
3
|
+
Version: 4.3.4
|
4
4
|
Summary: Components for modelling diseases, risks, and interventions with ``vivarium``
|
5
5
|
Home-page: https://github.com/ihmeuw/vivarium_public_health
|
6
6
|
Author: The vivarium developers
|
@@ -31,7 +31,7 @@ Requires-Dist: vivarium>=3.4.3
|
|
31
31
|
Requires-Dist: layered_config_tree>=3.2.0
|
32
32
|
Requires-Dist: loguru
|
33
33
|
Requires-Dist: numpy<2.0.0
|
34
|
-
Requires-Dist: pandas
|
34
|
+
Requires-Dist: pandas
|
35
35
|
Requires-Dist: scipy
|
36
36
|
Requires-Dist: tables
|
37
37
|
Requires-Dist: risk_distributions>=2.0.11
|
@@ -1,6 +1,6 @@
|
|
1
1
|
vivarium_public_health/__about__.py,sha256=RgWycPypKZS80TpSX7o41cREnG8PfguNHDHLuLyl820,487
|
2
|
-
vivarium_public_health/__init__.py,sha256=
|
3
|
-
vivarium_public_health/_version.py,sha256=
|
2
|
+
vivarium_public_health/__init__.py,sha256=GDeeP-7OlCBwPuv_xQoB1wNmvCaFsqfTB7qnnYApm0w,1343
|
3
|
+
vivarium_public_health/_version.py,sha256=215K0AQu12pX2_elDj3eHwDGWbBrLpNequvlrMryST8,22
|
4
4
|
vivarium_public_health/utilities.py,sha256=QNXQ6fhAr1HcV-GwKw7wQLz6QyuNxqNvMA-XujKjTgs,3035
|
5
5
|
vivarium_public_health/disease/__init__.py,sha256=VUJHDLlE6ngo2qHNQUtZ8OWH5H_T7_ao-xsYKDkRmHw,443
|
6
6
|
vivarium_public_health/disease/exceptions.py,sha256=vb30IIV82OiDf2cNZCs_E2rF6mdDDHbnZSND60no5CU,97
|
@@ -9,11 +9,6 @@ vivarium_public_health/disease/models.py,sha256=01UK7yB2zGPFzmlIpvhd-XnGe6vSCMDz
|
|
9
9
|
vivarium_public_health/disease/special_disease.py,sha256=4tGfnXSVuNYsA7izX9y81ByJe46c4h293szVt7AyPMA,14605
|
10
10
|
vivarium_public_health/disease/state.py,sha256=ptcNETOo8a0NRXOdUhZMgCJa2h3Pt5ZElhMOKonkD4c,28560
|
11
11
|
vivarium_public_health/disease/transition.py,sha256=HPvv1l322XiQcNXIgDTt3WvytxSbuz_2jyPj-spQE3Y,9209
|
12
|
-
vivarium_public_health/exposure/__init__.py,sha256=CgpEy1CCkfVEyKwKh3nknyWAv4wUuvqpHzbit7DOvzA,66
|
13
|
-
vivarium_public_health/exposure/data_transformations.py,sha256=SgdPKc95BBqgMNUdlAQM8k6iaXcpxnjk5B2ySTES1Yg,9269
|
14
|
-
vivarium_public_health/exposure/distributions.py,sha256=XSGDT1TR0HVr4Gqi_Mc7m9nz5aMiDrrfr0WTU572Vsk,20827
|
15
|
-
vivarium_public_health/exposure/effect.py,sha256=cb-as4133uUXntyV-vZ3hv1drE_ylCLd8upR978yOXk,14416
|
16
|
-
vivarium_public_health/exposure/exposure.py,sha256=woAPnhDSILhZ2D3cQkGQvSwniPhXKmaHcwH1XrsNmUc,9261
|
17
12
|
vivarium_public_health/mslt/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
18
13
|
vivarium_public_health/mslt/delay.py,sha256=_neQ8oL2IhCqH0hiM4Od4Eb8NfYjyjSoniq02PFieTw,22872
|
19
14
|
vivarium_public_health/mslt/disease.py,sha256=Kwy7cDqiE9yYCsLV_7pAP7ZOe7GWVHUBe39a-GOInVU,16867
|
@@ -26,32 +21,30 @@ vivarium_public_health/plugins/parser.py,sha256=WoUisq0d-PfJtSzKYZ6C-s-fYdQpNiRB
|
|
26
21
|
vivarium_public_health/population/__init__.py,sha256=x_9rB93q64Krw-kbBDI1-_U_JsPO1_QrL03AwiFlwXI,243
|
27
22
|
vivarium_public_health/population/add_new_birth_cohorts.py,sha256=x6A60GE_F3I8AgLABNJ-2ziiUj52lAd66uX5yc2vIDI,9038
|
28
23
|
vivarium_public_health/population/base_population.py,sha256=Wu797AL13KRLhXkYni_XocJBLfhfvCVgGeas08U3tCM,18898
|
29
|
-
vivarium_public_health/population/data_transformations.py,sha256=
|
24
|
+
vivarium_public_health/population/data_transformations.py,sha256=YHbwfb40EPbXsPW-Rk1s5d61rP8fqgDtMELB7OJG3mo,22662
|
30
25
|
vivarium_public_health/population/mortality.py,sha256=Mtv45FENNY0GlPIoVd3d3pRq01aEh4cjzNXIgEe6hMo,10364
|
31
|
-
vivarium_public_health/results/__init__.py,sha256=
|
26
|
+
vivarium_public_health/results/__init__.py,sha256=rKUZGlRXJgEyFY4a_WJeg3XnC0l34S5guYZ0N9JJS4E,319
|
32
27
|
vivarium_public_health/results/columns.py,sha256=V-L3JgTcsk51Zx9PcUwSgaE1iZjuGyfZ8aShPjynadU,495
|
33
28
|
vivarium_public_health/results/disability.py,sha256=OijmWbPkaxmMT4xJ44rWgPz67lVfcLtEloaNwnOiK_g,9459
|
34
29
|
vivarium_public_health/results/disease.py,sha256=ni599TKhV3YKQb8_rlnTVt9tIFq_SiM-z8qaoBEdO6s,11764
|
35
|
-
vivarium_public_health/results/intervention.py,sha256=M9cGZOamxaXUXy6dOchHE7RXKh43bXyk9SNeMDur6Nc,5004
|
36
30
|
vivarium_public_health/results/mortality.py,sha256=9L8tphHn2BEt5sSDkvSfcAyyhsGA_xylEjTed-fv0YI,9206
|
37
31
|
vivarium_public_health/results/observer.py,sha256=ADikaV6TvHVaysWoeux_DcvmzAFT7kpD6KtRSl16SaY,7277
|
38
32
|
vivarium_public_health/results/risk.py,sha256=bPZq2El00MZ5A6ttqA-wvbHLm4E3OZcEZOkqV_GENk4,5838
|
39
33
|
vivarium_public_health/results/simple_cause.py,sha256=ibdE6KwhDfQWntCVkOEooBcmUydEoupmd3_poHSHyu8,1007
|
40
34
|
vivarium_public_health/results/stratification.py,sha256=4I3YGHVabNAZENE7YboOtWsWU4X-8LUBJ9iwYMbpl6E,5387
|
41
35
|
vivarium_public_health/risks/__init__.py,sha256=z8DcnZGxqNVAyFZm2WAV-IVNGvrSS4izju_0DNe2Ghw,212
|
42
|
-
vivarium_public_health/risks/base_risk.py,sha256=
|
43
|
-
vivarium_public_health/risks/data_transformations.py,sha256=
|
44
|
-
vivarium_public_health/risks/distributions.py,sha256=
|
45
|
-
vivarium_public_health/risks/effect.py,sha256=
|
36
|
+
vivarium_public_health/risks/base_risk.py,sha256=XrZ5iytFabPS2_9-jI0dZQKK206yy_ZvCbReUoAVrAQ,10851
|
37
|
+
vivarium_public_health/risks/data_transformations.py,sha256=SgdPKc95BBqgMNUdlAQM8k6iaXcpxnjk5B2ySTES1Yg,9269
|
38
|
+
vivarium_public_health/risks/distributions.py,sha256=5gkurGTPqZczIKum5NgJ-DbJ2bxA1tRbLe7jKgCqkQg,18203
|
39
|
+
vivarium_public_health/risks/effect.py,sha256=Cw-V1rMPaAPZsirbUElPzksvNuXLQc8TIIk0hgaFzvA,21259
|
46
40
|
vivarium_public_health/risks/implementations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
47
|
-
vivarium_public_health/risks/implementations/low_birth_weight_and_short_gestation.py,sha256=
|
48
|
-
vivarium_public_health/treatment/__init__.py,sha256=
|
49
|
-
vivarium_public_health/treatment/intervention.py,sha256=A7vqrIUgmMggZnSoaOIf0xYHHwSzyG5huXYPk7j21R0,3223
|
41
|
+
vivarium_public_health/risks/implementations/low_birth_weight_and_short_gestation.py,sha256=wKVGHhdIas9WOrgA5wpwkSSDrZwBtaCqkZXfQH6jrkY,21159
|
42
|
+
vivarium_public_health/treatment/__init__.py,sha256=wONElu9aJbBYwpYIovYPYaN_GYfVhPXtTeFWSdQMgA0,222
|
50
43
|
vivarium_public_health/treatment/magic_wand.py,sha256=zg4I48G-l9fC6-qjvApbM1zNACJimZlX9ZZ9fdHKwvc,1985
|
51
44
|
vivarium_public_health/treatment/scale_up.py,sha256=_bsf9c_yVc7-q_-yBcXimISTUfYzPps1auH0uEf7sfQ,7048
|
52
45
|
vivarium_public_health/treatment/therapeutic_inertia.py,sha256=ZIHnpuszZwA_BkS53JbSLvpcnX_bqG2knwCUyUgkA9M,2362
|
53
|
-
vivarium_public_health-4.3.
|
54
|
-
vivarium_public_health-4.3.
|
55
|
-
vivarium_public_health-4.3.
|
56
|
-
vivarium_public_health-4.3.
|
57
|
-
vivarium_public_health-4.3.
|
46
|
+
vivarium_public_health-4.3.4.dist-info/licenses/LICENSE.txt,sha256=mN4bNLUQNcN9njYRc_3jCZkfPySVpmM6MRps104FxA4,1548
|
47
|
+
vivarium_public_health-4.3.4.dist-info/METADATA,sha256=nNlKCkVxNAu6ftFCGJ_-6o_4TRXBCeQ7nbGfEWgUd1E,4287
|
48
|
+
vivarium_public_health-4.3.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
49
|
+
vivarium_public_health-4.3.4.dist-info/top_level.txt,sha256=VVInlpzCFD0UNNhjOq_j-a29odzjwUwYFTGfvqbi4dY,23
|
50
|
+
vivarium_public_health-4.3.4.dist-info/RECORD,,
|