vivarium-public-health 3.0.2__py3-none-any.whl → 3.0.4__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- vivarium_public_health/_version.py +1 -1
- vivarium_public_health/disease/state.py +24 -19
- vivarium_public_health/mslt/delay.py +13 -5
- vivarium_public_health/mslt/disease.py +35 -14
- vivarium_public_health/mslt/intervention.py +12 -9
- vivarium_public_health/mslt/observer.py +56 -17
- vivarium_public_health/mslt/population.py +7 -10
- vivarium_public_health/plugins/parser.py +29 -80
- vivarium_public_health/population/add_new_birth_cohorts.py +12 -11
- vivarium_public_health/population/base_population.py +0 -5
- vivarium_public_health/population/data_transformations.py +1 -8
- vivarium_public_health/population/mortality.py +3 -3
- vivarium_public_health/results/columns.py +1 -1
- vivarium_public_health/results/disability.py +97 -16
- vivarium_public_health/results/disease.py +125 -2
- vivarium_public_health/results/mortality.py +78 -2
- vivarium_public_health/results/observer.py +141 -6
- vivarium_public_health/results/risk.py +66 -5
- vivarium_public_health/results/simple_cause.py +8 -2
- vivarium_public_health/results/stratification.py +39 -14
- vivarium_public_health/risks/base_risk.py +14 -16
- vivarium_public_health/risks/data_transformations.py +3 -1
- vivarium_public_health/risks/distributions.py +0 -1
- vivarium_public_health/risks/effect.py +31 -29
- vivarium_public_health/risks/implementations/low_birth_weight_and_short_gestation.py +51 -30
- vivarium_public_health/treatment/scale_up.py +6 -10
- vivarium_public_health/treatment/therapeutic_inertia.py +3 -1
- {vivarium_public_health-3.0.2.dist-info → vivarium_public_health-3.0.4.dist-info}/METADATA +1 -1
- vivarium_public_health-3.0.4.dist-info/RECORD +49 -0
- {vivarium_public_health-3.0.2.dist-info → vivarium_public_health-3.0.4.dist-info}/WHEEL +1 -1
- vivarium_public_health-3.0.2.dist-info/RECORD +0 -49
- {vivarium_public_health-3.0.2.dist-info → vivarium_public_health-3.0.4.dist-info}/LICENSE.txt +0 -0
- {vivarium_public_health-3.0.2.dist-info → vivarium_public_health-3.0.4.dist-info}/top_level.txt +0 -0
@@ -8,16 +8,19 @@ from vivarium_public_health.results.columns import COLUMNS
|
|
8
8
|
|
9
9
|
|
10
10
|
class PublicHealthObserver(Observer):
|
11
|
-
"""A convenience class for typical public health observers.
|
12
|
-
|
13
|
-
|
11
|
+
"""A convenience class for typical public health observers.
|
12
|
+
|
13
|
+
It exposes a method for registering the most common observation type
|
14
|
+
(adding observation) as well methods for formatting public health results
|
15
|
+
in a standardized way (to be overwritten as necessary).
|
16
|
+
|
14
17
|
"""
|
15
18
|
|
16
19
|
def register_adding_observation(
|
17
20
|
self,
|
18
21
|
builder: Builder,
|
19
|
-
name,
|
20
|
-
pop_filter,
|
22
|
+
name: str,
|
23
|
+
pop_filter: str,
|
21
24
|
when: str = "collect_metrics",
|
22
25
|
requires_columns: List[str] = [],
|
23
26
|
requires_values: List[str] = [],
|
@@ -25,7 +28,42 @@ class PublicHealthObserver(Observer):
|
|
25
28
|
excluded_stratifications: List[str] = [],
|
26
29
|
aggregator_sources: Optional[List[str]] = None,
|
27
30
|
aggregator: Callable[[pd.DataFrame], Union[float, pd.Series]] = len,
|
28
|
-
):
|
31
|
+
) -> None:
|
32
|
+
"""Registers an adding observation to the results system.
|
33
|
+
|
34
|
+
An "adding" observation is one that adds/sums new results to existing
|
35
|
+
result values. It is the most common type of observation used in public
|
36
|
+
health models.
|
37
|
+
|
38
|
+
Parameters
|
39
|
+
----------
|
40
|
+
builder
|
41
|
+
The builder object.
|
42
|
+
name
|
43
|
+
Name of the observation. It will also be the name of the output results
|
44
|
+
file for this particular observation.
|
45
|
+
pop_filter
|
46
|
+
A Pandas query filter string to filter the population down to the
|
47
|
+
simulants who should be considered for the observation.
|
48
|
+
when
|
49
|
+
Name of the lifecycle phase the observation should happen. Valid values are:
|
50
|
+
"time_step__prepare", "time_step", "time_step__cleanup", or "collect_metrics".
|
51
|
+
requires_columns
|
52
|
+
List of the state table columns that are required by either the `pop_filter`
|
53
|
+
or the `aggregator`.
|
54
|
+
requires_values
|
55
|
+
List of the value pipelines that are required by either the `pop_filter`
|
56
|
+
or the `aggregator`.
|
57
|
+
additional_stratifications
|
58
|
+
List of additional stratification names by which to stratify this
|
59
|
+
observation by.
|
60
|
+
excluded_stratifications
|
61
|
+
List of default stratification names to remove from this observation.
|
62
|
+
aggregator_sources
|
63
|
+
List of population view columns to be used in the `aggregator`.
|
64
|
+
aggregator
|
65
|
+
Function that computes the quantity for this observation.
|
66
|
+
"""
|
29
67
|
builder.results.register_adding_observation(
|
30
68
|
name=name,
|
31
69
|
pop_filter=pop_filter,
|
@@ -42,6 +80,27 @@ class PublicHealthObserver(Observer):
|
|
42
80
|
def format_results(self, measure: str, results: pd.DataFrame) -> pd.DataFrame:
|
43
81
|
"""Top-level results formatter that calls standard sub-methods to be
|
44
82
|
overwritten as necessary.
|
83
|
+
|
84
|
+
Public health observations typically require four columns in addition to
|
85
|
+
any stratifications and results columns: 'measure', 'entity_type', 'entity',
|
86
|
+
and 'sub_entity'. This method provides a standardized way to format
|
87
|
+
results by providing five sub-methods to be overwritten as necessary:
|
88
|
+
- format()
|
89
|
+
- get_measure_column()
|
90
|
+
- get_entity_type_column()
|
91
|
+
- get_entity_column()
|
92
|
+
- get_sub_entity_column()
|
93
|
+
|
94
|
+
Parameters
|
95
|
+
----------
|
96
|
+
measure
|
97
|
+
The measure name.
|
98
|
+
results
|
99
|
+
The raw results.
|
100
|
+
|
101
|
+
Returns
|
102
|
+
-------
|
103
|
+
The formatted results.
|
45
104
|
"""
|
46
105
|
|
47
106
|
results = self.format(measure, results)
|
@@ -63,16 +122,92 @@ class PublicHealthObserver(Observer):
|
|
63
122
|
return results[ordered_columns]
|
64
123
|
|
65
124
|
def format(self, measure: str, results: pd.DataFrame) -> pd.DataFrame:
|
125
|
+
"""Format results.
|
126
|
+
|
127
|
+
This method should be overwritten in subclasses to provide custom formatting
|
128
|
+
for the results.
|
129
|
+
|
130
|
+
Parameters
|
131
|
+
----------
|
132
|
+
measure
|
133
|
+
The measure name.
|
134
|
+
results
|
135
|
+
The raw results.
|
136
|
+
|
137
|
+
Returns
|
138
|
+
-------
|
139
|
+
The formatted results.
|
140
|
+
"""
|
66
141
|
return results
|
67
142
|
|
68
143
|
def get_measure_column(self, measure: str, results: pd.DataFrame) -> pd.Series:
|
144
|
+
"""Get the 'measure' column.
|
145
|
+
|
146
|
+
This method should be overwritten in subclasses to provide the 'measure' column.
|
147
|
+
|
148
|
+
Parameters
|
149
|
+
----------
|
150
|
+
measure
|
151
|
+
The measure name.
|
152
|
+
results
|
153
|
+
The raw results.
|
154
|
+
|
155
|
+
Returns
|
156
|
+
-------
|
157
|
+
The 'measure' column values.
|
158
|
+
"""
|
69
159
|
return pd.Series(measure, index=results.index)
|
70
160
|
|
71
161
|
def get_entity_type_column(self, measure: str, results: pd.DataFrame) -> pd.Series:
|
162
|
+
"""Get the 'entity_type' column.
|
163
|
+
|
164
|
+
This method should be overwritten in subclasses to provide the 'entity_type' column.
|
165
|
+
|
166
|
+
Parameters
|
167
|
+
----------
|
168
|
+
measure
|
169
|
+
The measure name.
|
170
|
+
results
|
171
|
+
The raw results.
|
172
|
+
|
173
|
+
Returns
|
174
|
+
-------
|
175
|
+
The 'entity_type' column values.
|
176
|
+
"""
|
72
177
|
return pd.Series(None, index=results.index)
|
73
178
|
|
74
179
|
def get_entity_column(self, measure: str, results: pd.DataFrame) -> pd.Series:
|
180
|
+
"""Get the 'entity' column.
|
181
|
+
|
182
|
+
This method should be overwritten in subclasses to provide the 'entity' column.
|
183
|
+
|
184
|
+
Parameters
|
185
|
+
----------
|
186
|
+
measure
|
187
|
+
The measure name.
|
188
|
+
results
|
189
|
+
The raw results.
|
190
|
+
|
191
|
+
Returns
|
192
|
+
-------
|
193
|
+
The 'entity' column values.
|
194
|
+
"""
|
75
195
|
return pd.Series(None, index=results.index)
|
76
196
|
|
77
197
|
def get_sub_entity_column(self, measure: str, results: pd.DataFrame) -> pd.Series:
|
198
|
+
"""Get the 'sub_entity' column.
|
199
|
+
|
200
|
+
This method should be overwritten in subclasses to provide the 'sub_entity' column.
|
201
|
+
|
202
|
+
Parameters
|
203
|
+
----------
|
204
|
+
measure
|
205
|
+
The measure name.
|
206
|
+
results
|
207
|
+
The raw results.
|
208
|
+
|
209
|
+
Returns
|
210
|
+
-------
|
211
|
+
The 'sub_entity' column values.
|
212
|
+
"""
|
78
213
|
return pd.Series(None, index=results.index)
|
@@ -40,6 +40,18 @@ class CategoricalRiskObserver(PublicHealthObserver):
|
|
40
40
|
- "sex"
|
41
41
|
include:
|
42
42
|
- "sample_stratification"
|
43
|
+
|
44
|
+
Attributes
|
45
|
+
----------
|
46
|
+
risk
|
47
|
+
The name of the risk factor.
|
48
|
+
exposure_pipeline_name
|
49
|
+
The name of the pipeline that produces the risk factor exposure.
|
50
|
+
step_size
|
51
|
+
The time step size of the simulation.
|
52
|
+
categories
|
53
|
+
The categories of the risk factor.
|
54
|
+
|
43
55
|
"""
|
44
56
|
|
45
57
|
##############
|
@@ -48,8 +60,7 @@ class CategoricalRiskObserver(PublicHealthObserver):
|
|
48
60
|
|
49
61
|
@property
|
50
62
|
def configuration_defaults(self) -> Dict[str, Any]:
|
51
|
-
"""
|
52
|
-
A dictionary containing the defaults for any configurations managed by
|
63
|
+
"""A dictionary containing the defaults for any configurations managed by
|
53
64
|
this component.
|
54
65
|
"""
|
55
66
|
return {
|
@@ -62,6 +73,7 @@ class CategoricalRiskObserver(PublicHealthObserver):
|
|
62
73
|
|
63
74
|
@property
|
64
75
|
def columns_required(self) -> Optional[List[str]]:
|
76
|
+
"""The columns required by this observer."""
|
65
77
|
return ["alive"]
|
66
78
|
|
67
79
|
#####################
|
@@ -69,11 +81,12 @@ class CategoricalRiskObserver(PublicHealthObserver):
|
|
69
81
|
#####################
|
70
82
|
|
71
83
|
def __init__(self, risk: str) -> None:
|
72
|
-
"""
|
84
|
+
"""Constructor for this observer.
|
85
|
+
|
73
86
|
Parameters
|
74
87
|
----------
|
75
|
-
risk
|
76
|
-
|
88
|
+
risk
|
89
|
+
The name of the risk being observed
|
77
90
|
"""
|
78
91
|
super().__init__()
|
79
92
|
self.risk = risk
|
@@ -84,13 +97,37 @@ class CategoricalRiskObserver(PublicHealthObserver):
|
|
84
97
|
#################
|
85
98
|
|
86
99
|
def setup(self, builder: Builder) -> None:
|
100
|
+
"""Set up the observer."""
|
87
101
|
self.step_size = builder.time.step_size()
|
88
102
|
self.categories = builder.data.load(f"risk_factor.{self.risk}.categories")
|
89
103
|
|
90
104
|
def get_configuration(self, builder: Builder) -> LayeredConfigTree:
|
105
|
+
"""Get the stratification configuration for this observer.
|
106
|
+
|
107
|
+
Parameters
|
108
|
+
----------
|
109
|
+
builder
|
110
|
+
The builder object for the simulation.
|
111
|
+
|
112
|
+
Returns
|
113
|
+
-------
|
114
|
+
The stratification configuration for this observer.
|
115
|
+
"""
|
91
116
|
return builder.configuration.stratification[self.risk]
|
92
117
|
|
93
118
|
def register_observations(self, builder: Builder) -> None:
|
119
|
+
"""Register a stratification and observation.
|
120
|
+
|
121
|
+
Notes
|
122
|
+
-----
|
123
|
+
While it's typical for all stratification registrations to be encapsulated
|
124
|
+
in a single class (i.e. the
|
125
|
+
:class:ResultsStratifier <vivarium_public_health.results.stratification.ResultsStratifier),
|
126
|
+
this observer registers an additional one. While it could be registered
|
127
|
+
in the ``ResultsStratifier`` as well, it is specific to this observer and
|
128
|
+
so it is registered here while we have easy access to the required categories
|
129
|
+
and value names.
|
130
|
+
"""
|
94
131
|
builder.results.register_stratification(
|
95
132
|
f"{self.risk}",
|
96
133
|
list(self.categories.keys()),
|
@@ -113,6 +150,7 @@ class CategoricalRiskObserver(PublicHealthObserver):
|
|
113
150
|
###############
|
114
151
|
|
115
152
|
def aggregate_risk_category_person_time(self, x: pd.DataFrame) -> float:
|
153
|
+
"""Aggregate the person time for this time step."""
|
116
154
|
return len(x) * to_years(self.step_size())
|
117
155
|
|
118
156
|
##############################
|
@@ -120,19 +158,42 @@ class CategoricalRiskObserver(PublicHealthObserver):
|
|
120
158
|
##############################
|
121
159
|
|
122
160
|
def format(self, measure: str, results: pd.DataFrame) -> pd.DataFrame:
|
161
|
+
"""Rename the appropriate column to 'sub_entity'.
|
162
|
+
|
163
|
+
The primary thing this method does is rename the risk column
|
164
|
+
to 'sub_entity'. We do this here instead of the 'get_sub_entity_column'
|
165
|
+
method simply because we do not want the risk column at all. If we keep
|
166
|
+
it here and then return it as the sub-entity column later, the final
|
167
|
+
results would have both.
|
168
|
+
|
169
|
+
Parameters
|
170
|
+
----------
|
171
|
+
measure
|
172
|
+
The measure.
|
173
|
+
results
|
174
|
+
The results to format.
|
175
|
+
|
176
|
+
Returns
|
177
|
+
-------
|
178
|
+
The formatted results.
|
179
|
+
"""
|
123
180
|
results = results.reset_index()
|
124
181
|
results.rename(columns={self.risk: COLUMNS.SUB_ENTITY}, inplace=True)
|
125
182
|
return results
|
126
183
|
|
127
184
|
def get_measure_column(self, measure: str, results: pd.DataFrame) -> pd.Series:
|
185
|
+
"""Get the 'measure' column values."""
|
128
186
|
return pd.Series("person_time", index=results.index)
|
129
187
|
|
130
188
|
def get_entity_type_column(self, measure: str, results: pd.DataFrame) -> pd.Series:
|
189
|
+
"""Get the 'entity_type' column values."""
|
131
190
|
return pd.Series("rei", index=results.index)
|
132
191
|
|
133
192
|
def get_entity_column(self, measure: str, results: pd.DataFrame) -> pd.Series:
|
193
|
+
"""Get the 'entity' column values."""
|
134
194
|
return pd.Series(self.risk, index=results.index)
|
135
195
|
|
136
196
|
def get_sub_entity_column(self, measure: str, results: pd.DataFrame) -> pd.Series:
|
197
|
+
"""Get the 'sub_entity' column values."""
|
137
198
|
# The sub-entity col was created in the 'format' method
|
138
199
|
return results[COLUMNS.SUB_ENTITY]
|
@@ -4,15 +4,21 @@ from dataclasses import dataclass
|
|
4
4
|
@dataclass
|
5
5
|
class SimpleCause:
|
6
6
|
"""A simple dataclass to represent the bare minimum information needed
|
7
|
-
for observers, e.g. 'all_causes' as a cause of disability.
|
8
|
-
|
7
|
+
for observers, e.g. 'all_causes' as a cause of disability.
|
8
|
+
|
9
|
+
It also includes a class method to convert a provided disease state into a
|
9
10
|
``SimpleCause`` instance.
|
11
|
+
|
10
12
|
"""
|
11
13
|
|
12
14
|
state_id: str
|
15
|
+
"""The state_id of the cause."""
|
13
16
|
model: str
|
17
|
+
"""The model of the cause."""
|
14
18
|
cause_type: str
|
19
|
+
"""The cause type of the cause."""
|
15
20
|
|
16
21
|
@classmethod
|
17
22
|
def create_from_disease_state(cls, disease_state: type) -> "SimpleCause":
|
23
|
+
"""Create a SimpleCause instance from a"""
|
18
24
|
return cls(disease_state.state_id, disease_state.model, disease_state.cause_type)
|
@@ -5,9 +5,8 @@ Results Stratifier
|
|
5
5
|
|
6
6
|
This module contains tools for stratifying observed quantities
|
7
7
|
by specified characteristics through the vivarium results interface.
|
8
|
-
"""
|
9
8
|
|
10
|
-
|
9
|
+
"""
|
11
10
|
|
12
11
|
import pandas as pd
|
13
12
|
from vivarium import Component
|
@@ -15,6 +14,22 @@ from vivarium.framework.engine import Builder
|
|
15
14
|
|
16
15
|
|
17
16
|
class ResultsStratifier(Component):
|
17
|
+
"""A component for registering common public health stratifications.
|
18
|
+
|
19
|
+
The purpose of this component is to encapsulate all common public health
|
20
|
+
stratification registrations in one place. This is not enforced, however,
|
21
|
+
and stratification registrations can be done in any component.
|
22
|
+
|
23
|
+
Attributes
|
24
|
+
----------
|
25
|
+
age_bins
|
26
|
+
The age bins for stratifying by age.
|
27
|
+
start_year
|
28
|
+
The start year of the simulation.
|
29
|
+
end_year
|
30
|
+
The end year of the simulation.
|
31
|
+
"""
|
32
|
+
|
18
33
|
#####################
|
19
34
|
# Lifecycle methods #
|
20
35
|
#####################
|
@@ -32,6 +47,7 @@ class ResultsStratifier(Component):
|
|
32
47
|
#################
|
33
48
|
|
34
49
|
def register_stratifications(self, builder: Builder) -> None:
|
50
|
+
"""Register stratifications for the simulation."""
|
35
51
|
builder.results.register_stratification(
|
36
52
|
"age_group",
|
37
53
|
self.age_bins["age_group_name"].to_list(),
|
@@ -80,18 +96,17 @@ class ResultsStratifier(Component):
|
|
80
96
|
# Mappers #
|
81
97
|
###########
|
82
98
|
|
83
|
-
def map_age_groups(self, pop: pd.DataFrame) -> pd.Series
|
84
|
-
"""Map age with age group name strings
|
99
|
+
def map_age_groups(self, pop: pd.DataFrame) -> pd.Series:
|
100
|
+
"""Map age with age group name strings.
|
85
101
|
|
86
102
|
Parameters
|
87
103
|
----------
|
88
104
|
pop
|
89
|
-
A
|
105
|
+
A table with one column, an age to be mapped to an age group name string.
|
90
106
|
|
91
107
|
Returns
|
92
|
-
|
93
|
-
|
94
|
-
A pd.Series with age group name string corresponding to the pop passed into the function
|
108
|
+
-------
|
109
|
+
The age group name strings corresponding to the pop passed into the function.
|
95
110
|
"""
|
96
111
|
bins = self.age_bins["age_start"].to_list() + [self.age_bins["age_end"].iloc[-1]]
|
97
112
|
labels = self.age_bins["age_group_name"].to_list()
|
@@ -99,23 +114,33 @@ class ResultsStratifier(Component):
|
|
99
114
|
return age_group
|
100
115
|
|
101
116
|
@staticmethod
|
102
|
-
def map_year(pop: pd.DataFrame) -> pd.Series
|
103
|
-
"""Map datetime with year
|
117
|
+
def map_year(pop: pd.DataFrame) -> pd.Series:
|
118
|
+
"""Map datetime with year.
|
104
119
|
|
105
120
|
Parameters
|
106
121
|
----------
|
107
122
|
pop
|
108
|
-
A
|
123
|
+
A table with one column, a datetime to be mapped to year.
|
109
124
|
|
110
125
|
Returns
|
111
|
-
|
112
|
-
|
113
|
-
A pd.Series with years corresponding to the pop passed into the function
|
126
|
+
-------
|
127
|
+
The years corresponding to the pop passed into the function.
|
114
128
|
"""
|
115
129
|
return pop.squeeze(axis=1).dt.year.apply(str)
|
116
130
|
|
117
131
|
@staticmethod
|
118
132
|
def get_age_bins(builder: Builder) -> pd.DataFrame:
|
133
|
+
"""Get the age bins for stratifying by age.
|
134
|
+
|
135
|
+
Parameters
|
136
|
+
----------
|
137
|
+
builder
|
138
|
+
The builder object for the simulation.
|
139
|
+
|
140
|
+
Returns
|
141
|
+
-------
|
142
|
+
The age bins for stratifying by age.
|
143
|
+
"""
|
119
144
|
raw_age_bins = builder.data.load("population.age_bins")
|
120
145
|
age_start = builder.configuration.population.initialization_age_min
|
121
146
|
exit_age = builder.configuration.population.untracking_age
|
@@ -30,8 +30,9 @@ from vivarium_public_health.utilities import EntityString, get_lookup_columns
|
|
30
30
|
|
31
31
|
|
32
32
|
class Risk(Component):
|
33
|
-
"""A model for a risk factor defined by either a continuous or a categorical
|
34
|
-
|
33
|
+
"""A model for a risk factor defined by either a continuous or a categorical value.
|
34
|
+
|
35
|
+
For example,
|
35
36
|
|
36
37
|
#. high systolic blood pressure as a risk where the SBP is not dichotomized
|
37
38
|
into hypotension and normal but is treated as the actual SBP
|
@@ -138,9 +139,10 @@ class Risk(Component):
|
|
138
139
|
|
139
140
|
def __init__(self, risk: str):
|
140
141
|
"""
|
142
|
+
|
141
143
|
Parameters
|
142
144
|
----------
|
143
|
-
risk
|
145
|
+
risk
|
144
146
|
the type and name of a risk, specified as "type.name". Type is singular.
|
145
147
|
"""
|
146
148
|
super().__init__()
|
@@ -171,8 +173,7 @@ class Risk(Component):
|
|
171
173
|
self.exposure = self.get_exposure_pipeline(builder)
|
172
174
|
|
173
175
|
def get_distribution_type(self, builder: Builder) -> str:
|
174
|
-
"""
|
175
|
-
Get the distribution type for the risk from the configuration.
|
176
|
+
"""Get the distribution type for the risk from the configuration.
|
176
177
|
|
177
178
|
If the configured distribution type is not one of the supported types,
|
178
179
|
it is assumed to be a data source and the data is retrieved using the
|
@@ -180,13 +181,12 @@ class Risk(Component):
|
|
180
181
|
|
181
182
|
Parameters
|
182
183
|
----------
|
183
|
-
builder
|
184
|
-
|
184
|
+
builder
|
185
|
+
The builder object.
|
185
186
|
|
186
187
|
Returns
|
187
188
|
-------
|
188
|
-
|
189
|
-
the distribution type
|
189
|
+
The distribution type.
|
190
190
|
"""
|
191
191
|
if self.configuration is None:
|
192
192
|
self.configuration = self.get_configuration(builder)
|
@@ -207,24 +207,22 @@ class Risk(Component):
|
|
207
207
|
return distribution_type
|
208
208
|
|
209
209
|
def get_exposure_distribution(self, builder: Builder) -> RiskExposureDistribution:
|
210
|
-
"""
|
211
|
-
Creates and sets up the exposure distribution component for the Risk
|
210
|
+
"""Creates and sets up the exposure distribution component for the Risk
|
212
211
|
based on its distribution type.
|
213
212
|
|
214
213
|
Parameters
|
215
214
|
----------
|
216
|
-
builder
|
217
|
-
|
215
|
+
builder
|
216
|
+
The builder object.
|
218
217
|
|
219
218
|
Returns
|
220
219
|
-------
|
221
|
-
|
222
|
-
the exposure distribution
|
220
|
+
The exposure distribution.
|
223
221
|
|
224
222
|
Raises
|
225
223
|
------
|
226
224
|
NotImplementedError
|
227
|
-
|
225
|
+
If the distribution type is not supported.
|
228
226
|
"""
|
229
227
|
try:
|
230
228
|
exposure_distribution = self.exposure_distributions[self.distribution_type](
|
@@ -78,7 +78,9 @@ def load_exposure_data(builder: Builder, risk: EntityString) -> pd.DataFrame:
|
|
78
78
|
def rebin_relative_risk_data(
|
79
79
|
builder, risk: EntityString, relative_risk_data: pd.DataFrame
|
80
80
|
) -> pd.DataFrame:
|
81
|
-
"""
|
81
|
+
"""Rebin relative risk data if necessary.
|
82
|
+
|
83
|
+
When the polytomous risk is rebinned, matching relative risk needs to be rebinned.
|
82
84
|
After rebinning, rr for both exposed and unexposed categories should be the weighted sum of relative risk
|
83
85
|
of the component categories where weights are relative proportions of exposure of those categories.
|
84
86
|
For example, if cat1, cat2, cat3 are exposed categories and cat4 is unexposed with exposure [0.1,0.2,0.3,0.4],
|
@@ -17,8 +17,6 @@ import scipy
|
|
17
17
|
from layered_config_tree import ConfigurationError
|
18
18
|
from vivarium import Component
|
19
19
|
from vivarium.framework.engine import Builder
|
20
|
-
from vivarium.framework.event import Event
|
21
|
-
from vivarium.framework.population import SimulantData
|
22
20
|
|
23
21
|
from vivarium_public_health.risks import Risk
|
24
22
|
from vivarium_public_health.risks.data_transformations import (
|
@@ -30,10 +28,12 @@ from vivarium_public_health.utilities import EntityString, TargetString, get_loo
|
|
30
28
|
|
31
29
|
|
32
30
|
class RiskEffect(Component):
|
33
|
-
"""A component to model the
|
34
|
-
|
35
|
-
builder.data or from parameters
|
36
|
-
|
31
|
+
"""A component to model the effect of a risk factor on an affected entity's target rate.
|
32
|
+
|
33
|
+
This component can source data either from builder.data or from parameters
|
34
|
+
supplied in the configuration.
|
35
|
+
|
36
|
+
For a risk named 'risk' that affects 'affected_risk' and 'affected_cause',
|
37
37
|
the configuration would look like:
|
38
38
|
|
39
39
|
.. code-block:: yaml
|
@@ -59,10 +59,7 @@ class RiskEffect(Component):
|
|
59
59
|
|
60
60
|
@property
|
61
61
|
def configuration_defaults(self) -> Dict[str, Any]:
|
62
|
-
"""
|
63
|
-
A dictionary containing the defaults for any configurations managed by
|
64
|
-
this component.
|
65
|
-
"""
|
62
|
+
"""Default values for any configurations managed by this component."""
|
66
63
|
return {
|
67
64
|
self.name: {
|
68
65
|
"data_sources": {
|
@@ -89,13 +86,14 @@ class RiskEffect(Component):
|
|
89
86
|
|
90
87
|
def __init__(self, risk: str, target: str):
|
91
88
|
"""
|
89
|
+
|
92
90
|
Parameters
|
93
91
|
----------
|
94
|
-
risk
|
92
|
+
risk
|
95
93
|
Type and name of risk factor, supplied in the form
|
96
94
|
"risk_type.risk_name" where risk_type should be singular (e.g.,
|
97
95
|
risk_factor instead of risk_factors).
|
98
|
-
target
|
96
|
+
target
|
99
97
|
Type, name, and target rate of entity to be affected by risk factor,
|
100
98
|
supplied in the form "entity_type.entity_name.measure"
|
101
99
|
where entity_type should be singular (e.g., cause instead of causes).
|
@@ -210,7 +208,9 @@ class RiskEffect(Component):
|
|
210
208
|
def rebin_relative_risk_data(
|
211
209
|
self, builder, relative_risk_data: pd.DataFrame
|
212
210
|
) -> pd.DataFrame:
|
213
|
-
"""
|
211
|
+
"""Rebin relative risk data.
|
212
|
+
|
213
|
+
When the polytomous risk is rebinned, matching relative risk needs to be rebinned.
|
214
214
|
After rebinning, rr for both exposed and unexposed categories should be the weighted sum of relative risk
|
215
215
|
of the component categories where weights are relative proportions of exposure of those categories.
|
216
216
|
For example, if cat1, cat2, cat3 are exposed categories and cat4 is unexposed with exposure [0.1,0.2,0.3,0.4],
|
@@ -319,18 +319,22 @@ class RiskEffect(Component):
|
|
319
319
|
|
320
320
|
|
321
321
|
class NonLogLinearRiskEffect(RiskEffect):
|
322
|
-
"""A component to model the
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
322
|
+
"""A component to model the exposure-parametrized effect of a risk factor.
|
323
|
+
|
324
|
+
More specifically, this models the effect of the risk factor on the target rate of
|
325
|
+
some affected entity.
|
326
|
+
|
327
|
+
This component:
|
328
|
+
1) reads TMRED data from the artifact and define the TMREL
|
329
|
+
2) calculates the relative risk at TMREL by linearly interpolating over
|
330
|
+
relative risk data defined in the configuration
|
331
|
+
3) divides relative risk data from configuration by RR at TMREL
|
332
|
+
and clip to be greater than 1
|
333
|
+
4) builds a LookupTable which returns the exposure and RR of the left and right edges
|
334
|
+
of the RR bin containing a simulant's exposure
|
335
|
+
5) uses this LookupTable to modify the target pipeline by linearly interpolating
|
336
|
+
a simulant's RR value and multiplying it by the intended target rate
|
337
|
+
|
334
338
|
"""
|
335
339
|
|
336
340
|
##############
|
@@ -339,10 +343,7 @@ class NonLogLinearRiskEffect(RiskEffect):
|
|
339
343
|
|
340
344
|
@property
|
341
345
|
def configuration_defaults(self) -> Dict[str, Any]:
|
342
|
-
"""
|
343
|
-
A dictionary containing the defaults for any configurations managed by
|
344
|
-
this component.
|
345
|
-
"""
|
346
|
+
"""Default values for any configurations managed by this component."""
|
346
347
|
return {
|
347
348
|
self.name: {
|
348
349
|
"data_sources": {
|
@@ -485,6 +486,7 @@ class NonLogLinearRiskEffect(RiskEffect):
|
|
485
486
|
##############
|
486
487
|
|
487
488
|
def validate_rr_data(self, rr_data: pd.DataFrame) -> None:
|
489
|
+
"""Validate the relative risk data."""
|
488
490
|
# check that rr_data has numeric parameter data
|
489
491
|
parameter_data_is_numeric = rr_data["parameter"].dtype.kind in "biufc"
|
490
492
|
if not parameter_data_is_numeric:
|