vivarium-public-health 3.0.3__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 +8 -9
- 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 +85 -11
- 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.3.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.3.dist-info → vivarium_public_health-3.0.4.dist-info}/WHEEL +1 -1
- vivarium_public_health-3.0.3.dist-info/RECORD +0 -49
- {vivarium_public_health-3.0.3.dist-info → vivarium_public_health-3.0.4.dist-info}/LICENSE.txt +0 -0
- {vivarium_public_health-3.0.3.dist-info → vivarium_public_health-3.0.4.dist-info}/top_level.txt +0 -0
@@ -41,6 +41,24 @@ class DiseaseObserver(PublicHealthObserver):
|
|
41
41
|
- "sex"
|
42
42
|
include:
|
43
43
|
- "sample_stratification"
|
44
|
+
|
45
|
+
Attributes
|
46
|
+
----------
|
47
|
+
disease
|
48
|
+
The name of the disease being observed.
|
49
|
+
previous_state_column_name
|
50
|
+
The name of the column that stores the previous state of the disease.
|
51
|
+
step_size
|
52
|
+
The time step size of the simulation.
|
53
|
+
disease_model
|
54
|
+
The disease model for the disease being observed.
|
55
|
+
entity_type
|
56
|
+
The type of entity being observed.
|
57
|
+
entity
|
58
|
+
The entity being observed.
|
59
|
+
transition_stratification_name
|
60
|
+
The stratification name for transitions between disease states.
|
61
|
+
|
44
62
|
"""
|
45
63
|
|
46
64
|
##############
|
@@ -49,6 +67,9 @@ class DiseaseObserver(PublicHealthObserver):
|
|
49
67
|
|
50
68
|
@property
|
51
69
|
def configuration_defaults(self) -> Dict[str, Any]:
|
70
|
+
"""A dictionary containing the defaults for any configurations managed by
|
71
|
+
this component.
|
72
|
+
"""
|
52
73
|
return {
|
53
74
|
"stratification": {
|
54
75
|
self.disease: super().configuration_defaults["stratification"][
|
@@ -59,14 +80,17 @@ class DiseaseObserver(PublicHealthObserver):
|
|
59
80
|
|
60
81
|
@property
|
61
82
|
def columns_created(self) -> List[str]:
|
83
|
+
"""Columns created by this observer."""
|
62
84
|
return [self.previous_state_column_name]
|
63
85
|
|
64
86
|
@property
|
65
87
|
def columns_required(self) -> List[str]:
|
88
|
+
"""Columns required by this observer."""
|
66
89
|
return [self.disease]
|
67
90
|
|
68
91
|
@property
|
69
92
|
def initialization_requirements(self) -> Dict[str, List[str]]:
|
93
|
+
"""Requirements for observer initialization."""
|
70
94
|
return {
|
71
95
|
"requires_columns": [self.disease],
|
72
96
|
}
|
@@ -76,6 +100,13 @@ class DiseaseObserver(PublicHealthObserver):
|
|
76
100
|
#####################
|
77
101
|
|
78
102
|
def __init__(self, disease: str) -> None:
|
103
|
+
"""Constructor for this observer.
|
104
|
+
|
105
|
+
Parameters
|
106
|
+
----------
|
107
|
+
disease
|
108
|
+
The name of the disease being observed.
|
109
|
+
"""
|
79
110
|
super().__init__()
|
80
111
|
self.disease = disease
|
81
112
|
self.previous_state_column_name = f"previous_{self.disease}"
|
@@ -85,6 +116,7 @@ class DiseaseObserver(PublicHealthObserver):
|
|
85
116
|
#################
|
86
117
|
|
87
118
|
def setup(self, builder: Builder) -> None:
|
119
|
+
"""Set up the observer."""
|
88
120
|
self.step_size = builder.time.step_size()
|
89
121
|
self.disease_model = builder.components.get_component(f"disease_model.{self.disease}")
|
90
122
|
self.entity_type = self.disease_model.cause_type
|
@@ -92,10 +124,35 @@ class DiseaseObserver(PublicHealthObserver):
|
|
92
124
|
self.transition_stratification_name = f"transition_{self.disease}"
|
93
125
|
|
94
126
|
def get_configuration(self, builder: Builder) -> LayeredConfigTree:
|
127
|
+
"""Get the stratification configuration for this observer.
|
128
|
+
|
129
|
+
Parameters
|
130
|
+
----------
|
131
|
+
builder
|
132
|
+
The builder object for the simulation.
|
133
|
+
|
134
|
+
Returns
|
135
|
+
-------
|
136
|
+
The stratification configuration for this observer.
|
137
|
+
"""
|
95
138
|
return builder.configuration.stratification[self.disease]
|
96
139
|
|
97
140
|
def register_observations(self, builder: Builder) -> None:
|
98
|
-
|
141
|
+
"""Register stratifications and observations.
|
142
|
+
|
143
|
+
Notes
|
144
|
+
-----
|
145
|
+
Ideally, each observer registers a single observation. This one, however,
|
146
|
+
registeres two.
|
147
|
+
|
148
|
+
While it's typical for all stratification registrations to be encapsulated
|
149
|
+
in a single class (i.e. the
|
150
|
+
:class:ResultsStratifier <vivarium_public_health.results.stratification.ResultsStratifier),
|
151
|
+
this observer registers two additional stratifications. While they could
|
152
|
+
be registered in the ``ResultsStratifier`` as well, they are specific to
|
153
|
+
this observer and so they are registered here while we have easy access
|
154
|
+
to the required names and categories.
|
155
|
+
"""
|
99
156
|
self.register_disease_state_stratification(builder)
|
100
157
|
self.register_transition_stratification(builder)
|
101
158
|
|
@@ -104,6 +161,7 @@ class DiseaseObserver(PublicHealthObserver):
|
|
104
161
|
self.register_transition_count_observation(builder, pop_filter)
|
105
162
|
|
106
163
|
def register_disease_state_stratification(self, builder: Builder) -> None:
|
164
|
+
"""Register the disease state stratification."""
|
107
165
|
builder.results.register_stratification(
|
108
166
|
self.disease,
|
109
167
|
[state.state_id for state in self.disease_model.states],
|
@@ -111,6 +169,20 @@ class DiseaseObserver(PublicHealthObserver):
|
|
111
169
|
)
|
112
170
|
|
113
171
|
def register_transition_stratification(self, builder: Builder) -> None:
|
172
|
+
"""Register the transition stratification.
|
173
|
+
|
174
|
+
This stratification is used to track transitions between disease states.
|
175
|
+
It appends 'no_transition' to the list of transition categories and also
|
176
|
+
includes it as an exluded category.
|
177
|
+
|
178
|
+
Notes
|
179
|
+
-----
|
180
|
+
It is important to include 'no_transition' in bith the list of transition
|
181
|
+
categories as well as the list of excluded categories. This is because
|
182
|
+
it must exist as a category for the transition mapping to work correctly,
|
183
|
+
but then we don't want to include it later during the actual stratification
|
184
|
+
process.
|
185
|
+
"""
|
114
186
|
transitions = [
|
115
187
|
str(transition) for transition in self.disease_model.transition_names
|
116
188
|
] + ["no_transition"]
|
@@ -130,6 +202,7 @@ class DiseaseObserver(PublicHealthObserver):
|
|
130
202
|
)
|
131
203
|
|
132
204
|
def register_person_time_observation(self, builder: Builder, pop_filter: str) -> None:
|
205
|
+
"""Register a person time observation."""
|
133
206
|
self.register_adding_observation(
|
134
207
|
builder=builder,
|
135
208
|
name=f"person_time_{self.disease}",
|
@@ -144,6 +217,7 @@ class DiseaseObserver(PublicHealthObserver):
|
|
144
217
|
def register_transition_count_observation(
|
145
218
|
self, builder: Builder, pop_filter: str
|
146
219
|
) -> None:
|
220
|
+
"""Register a transition count observation."""
|
147
221
|
self.register_adding_observation(
|
148
222
|
builder=builder,
|
149
223
|
name=f"transition_count_{self.disease}",
|
@@ -158,6 +232,17 @@ class DiseaseObserver(PublicHealthObserver):
|
|
158
232
|
)
|
159
233
|
|
160
234
|
def map_transitions(self, df: pd.DataFrame) -> pd.Series:
|
235
|
+
"""Map previous and current disease states to transition string.
|
236
|
+
|
237
|
+
Parameters
|
238
|
+
----------
|
239
|
+
df
|
240
|
+
The DataFrame containing the disease states.
|
241
|
+
|
242
|
+
Returns
|
243
|
+
-------
|
244
|
+
The transitions between disease states.
|
245
|
+
"""
|
161
246
|
transitions = pd.Series(index=df.index, dtype=str)
|
162
247
|
transition_mask = df[self.previous_state_column_name] != df[self.disease]
|
163
248
|
transitions[~transition_mask] = "no_transition"
|
@@ -179,7 +264,10 @@ class DiseaseObserver(PublicHealthObserver):
|
|
179
264
|
self.population_view.update(pop)
|
180
265
|
|
181
266
|
def on_time_step_prepare(self, event: Event) -> None:
|
182
|
-
|
267
|
+
"""Update the previous state column to the current state.
|
268
|
+
|
269
|
+
This enables tracking of transitions between states.
|
270
|
+
"""
|
183
271
|
prior_state_pop = self.population_view.get(event.index)
|
184
272
|
prior_state_pop[self.previous_state_column_name] = prior_state_pop[self.disease]
|
185
273
|
self.population_view.update(prior_state_pop)
|
@@ -189,6 +277,17 @@ class DiseaseObserver(PublicHealthObserver):
|
|
189
277
|
###############
|
190
278
|
|
191
279
|
def aggregate_state_person_time(self, x: pd.DataFrame) -> float:
|
280
|
+
"""Aggregate person time for the time step.
|
281
|
+
|
282
|
+
Parameters
|
283
|
+
----------
|
284
|
+
x
|
285
|
+
The DataFrame containing the population.
|
286
|
+
|
287
|
+
Returns
|
288
|
+
-------
|
289
|
+
The aggregated person time.
|
290
|
+
"""
|
192
291
|
return len(x) * to_years(self.step_size())
|
193
292
|
|
194
293
|
##############################
|
@@ -196,6 +295,26 @@ class DiseaseObserver(PublicHealthObserver):
|
|
196
295
|
##############################
|
197
296
|
|
198
297
|
def format(self, measure: str, results: pd.DataFrame) -> pd.DataFrame:
|
298
|
+
"""Rename the appropriate column to 'sub_entity'.
|
299
|
+
|
300
|
+
The primary thing this method does is rename the appropriate column
|
301
|
+
(either the transition stratification name of the disease name, depending
|
302
|
+
on the measure) to 'sub_entity'. We do this here instead of the
|
303
|
+
'get_sub_entity_column' method simply because we do not want the original
|
304
|
+
column at all. If we keep it here and then return it as the sub-entity
|
305
|
+
column later, the final results would have both.
|
306
|
+
|
307
|
+
Parameters
|
308
|
+
----------
|
309
|
+
measure
|
310
|
+
The measure.
|
311
|
+
results
|
312
|
+
The results to format.
|
313
|
+
|
314
|
+
Returns
|
315
|
+
-------
|
316
|
+
The formatted results.
|
317
|
+
"""
|
199
318
|
results = results.reset_index()
|
200
319
|
if "transition_count_" in measure:
|
201
320
|
sub_entity = self.transition_stratification_name
|
@@ -205,6 +324,7 @@ class DiseaseObserver(PublicHealthObserver):
|
|
205
324
|
return results
|
206
325
|
|
207
326
|
def get_measure_column(self, measure: str, results: pd.DataFrame) -> pd.Series:
|
327
|
+
"""Get the 'measure' column values."""
|
208
328
|
if "transition_count_" in measure:
|
209
329
|
measure_name = "transition_count"
|
210
330
|
if "person_time_" in measure:
|
@@ -212,11 +332,14 @@ class DiseaseObserver(PublicHealthObserver):
|
|
212
332
|
return pd.Series(measure_name, index=results.index)
|
213
333
|
|
214
334
|
def get_entity_type_column(self, measure: str, results: pd.DataFrame) -> pd.Series:
|
335
|
+
"""Get the 'entity_type' column values."""
|
215
336
|
return pd.Series(self.entity_type, index=results.index)
|
216
337
|
|
217
338
|
def get_entity_column(self, measure: str, results: pd.DataFrame) -> pd.Series:
|
339
|
+
"""Get the 'entity' column values."""
|
218
340
|
return pd.Series(self.entity, index=results.index)
|
219
341
|
|
220
342
|
def get_sub_entity_column(self, measure: str, results: pd.DataFrame) -> pd.Series:
|
343
|
+
"""Get the 'sub_entity' column values."""
|
221
344
|
# The sub-entity col was created in the 'format' method
|
222
345
|
return results[COLUMNS.SUB_ENTITY]
|
@@ -47,6 +47,18 @@ class MortalityObserver(PublicHealthObserver):
|
|
47
47
|
This observer needs to access the has_excess_mortality attribute of the causes
|
48
48
|
we're observing, but this attribute gets defined in the setup of the cause models.
|
49
49
|
As a result, the model specification should list this observer after causes.
|
50
|
+
|
51
|
+
Attributes
|
52
|
+
----------
|
53
|
+
required_death_columns
|
54
|
+
Columns required by the deaths observation.
|
55
|
+
required_yll_columns
|
56
|
+
Columns required by the ylls observation.
|
57
|
+
clock
|
58
|
+
The simulation clock.
|
59
|
+
causes_of_death
|
60
|
+
Causes of death to be observed.
|
61
|
+
|
50
62
|
"""
|
51
63
|
|
52
64
|
def __init__(self) -> None:
|
@@ -65,12 +77,12 @@ class MortalityObserver(PublicHealthObserver):
|
|
65
77
|
|
66
78
|
@property
|
67
79
|
def mortality_classes(self) -> list[type]:
|
80
|
+
"""The classes to be considered as causes of death."""
|
68
81
|
return [DiseaseState, RiskAttributableDisease]
|
69
82
|
|
70
83
|
@property
|
71
84
|
def configuration_defaults(self) -> Dict[str, Any]:
|
72
|
-
"""
|
73
|
-
A dictionary containing the defaults for any configurations managed by
|
85
|
+
"""A dictionary containing the defaults for any configurations managed by
|
74
86
|
this component.
|
75
87
|
"""
|
76
88
|
config_defaults = super().configuration_defaults
|
@@ -79,6 +91,7 @@ class MortalityObserver(PublicHealthObserver):
|
|
79
91
|
|
80
92
|
@property
|
81
93
|
def columns_required(self) -> List[str]:
|
94
|
+
"""Columns required by this observer."""
|
82
95
|
return [
|
83
96
|
"alive",
|
84
97
|
"years_of_life_lost",
|
@@ -91,10 +104,22 @@ class MortalityObserver(PublicHealthObserver):
|
|
91
104
|
#################
|
92
105
|
|
93
106
|
def setup(self, builder: Builder) -> None:
|
107
|
+
"""Set up the observer."""
|
94
108
|
self.clock = builder.time.clock()
|
95
109
|
self.set_causes_of_death(builder)
|
96
110
|
|
97
111
|
def set_causes_of_death(self, builder: Builder) -> None:
|
112
|
+
"""Set the causes of death to be observed.
|
113
|
+
|
114
|
+
The causes to be observed are any registered components of class types
|
115
|
+
found in the ``mortality_classes`` property.
|
116
|
+
|
117
|
+
Notes
|
118
|
+
-----
|
119
|
+
We do not actually exclude any categories in this method.
|
120
|
+
|
121
|
+
Also note that we add 'not_dead' and 'other_causes' categories here.
|
122
|
+
"""
|
98
123
|
causes_of_death = [
|
99
124
|
cause
|
100
125
|
for cause in builder.components.get_components_by_type(
|
@@ -112,9 +137,35 @@ class MortalityObserver(PublicHealthObserver):
|
|
112
137
|
]
|
113
138
|
|
114
139
|
def get_configuration(self, builder: Builder) -> LayeredConfigTree:
|
140
|
+
"""Get the stratification configuration for this observer.
|
141
|
+
|
142
|
+
Parameters
|
143
|
+
----------
|
144
|
+
builder
|
145
|
+
The builder object for the simulation.
|
146
|
+
|
147
|
+
Returns
|
148
|
+
-------
|
149
|
+
The stratification configuration for this observer.
|
150
|
+
"""
|
115
151
|
return builder.configuration.stratification[self.get_configuration_name()]
|
116
152
|
|
117
153
|
def register_observations(self, builder: Builder) -> None:
|
154
|
+
"""Register stratifications and observations.
|
155
|
+
|
156
|
+
Notes
|
157
|
+
-----
|
158
|
+
Ideally, each observer registers a single observation. This one, however,
|
159
|
+
registeres two.
|
160
|
+
|
161
|
+
While it's typical for all stratification registrations to be encapsulated
|
162
|
+
in a single class (i.e. the
|
163
|
+
:class:ResultsStratifier <vivarium_public_health.results.stratification.ResultsStratifier),
|
164
|
+
this observer potentially registers an additional one. While it could
|
165
|
+
be registered in the ``ResultsStratifier`` as well, it is specific to
|
166
|
+
this observer and so it is registered here while we have easy access
|
167
|
+
to the required categories.
|
168
|
+
"""
|
118
169
|
pop_filter = 'alive == "dead" and tracked == True'
|
119
170
|
additional_stratifications = self.configuration.include
|
120
171
|
if not self.configuration.aggregate:
|
@@ -155,10 +206,12 @@ class MortalityObserver(PublicHealthObserver):
|
|
155
206
|
###############
|
156
207
|
|
157
208
|
def count_deaths(self, x: pd.DataFrame) -> float:
|
209
|
+
"""Count the number of deaths that occurred during this time step."""
|
158
210
|
died_of_cause = x["exit_time"] > self.clock()
|
159
211
|
return sum(died_of_cause)
|
160
212
|
|
161
213
|
def calculate_ylls(self, x: pd.DataFrame) -> float:
|
214
|
+
"""Calculate the years of life lost during this time step."""
|
162
215
|
died_of_cause = x["exit_time"] > self.clock()
|
163
216
|
return x.loc[died_of_cause, "years_of_life_lost"].sum()
|
164
217
|
|
@@ -167,6 +220,26 @@ class MortalityObserver(PublicHealthObserver):
|
|
167
220
|
##############################
|
168
221
|
|
169
222
|
def format(self, measure: str, results: pd.DataFrame) -> pd.DataFrame:
|
223
|
+
"""Rename the appropriate column to 'entity'.
|
224
|
+
|
225
|
+
The primary thing this method does is rename the 'cause_of_death' column
|
226
|
+
to 'entity' (or, it we are aggregating, and there is no 'cause_of_death'
|
227
|
+
column, we simply create a new 'entity' column). We do this here instead
|
228
|
+
of the 'get_entity_column' method simply because we do not want the
|
229
|
+
'cause_of_death' at all. If we keep it here and then return it as the
|
230
|
+
entity column later, the final results would have both.
|
231
|
+
|
232
|
+
Parameters
|
233
|
+
----------
|
234
|
+
measure
|
235
|
+
The measure.
|
236
|
+
results
|
237
|
+
The results to format.
|
238
|
+
|
239
|
+
Returns
|
240
|
+
-------
|
241
|
+
The formatted results.
|
242
|
+
"""
|
170
243
|
results = results.reset_index()
|
171
244
|
if self.configuration.aggregate:
|
172
245
|
results[COLUMNS.ENTITY] = "all_causes"
|
@@ -175,12 +248,15 @@ class MortalityObserver(PublicHealthObserver):
|
|
175
248
|
return results
|
176
249
|
|
177
250
|
def get_entity_type_column(self, measure: str, results: pd.DataFrame) -> pd.Series:
|
251
|
+
"""Get the 'entity_type' column values."""
|
178
252
|
entity_type_map = {cause.state_id: cause.cause_type for cause in self.causes_of_death}
|
179
253
|
return results[COLUMNS.ENTITY].map(entity_type_map).astype(CategoricalDtype())
|
180
254
|
|
181
255
|
def get_entity_column(self, measure: str, results: pd.DataFrame) -> pd.Series:
|
256
|
+
"""Get the 'entity' column values."""
|
182
257
|
# The entity col was created in the 'format' method
|
183
258
|
return results[COLUMNS.ENTITY]
|
184
259
|
|
185
260
|
def get_sub_entity_column(self, measure: str, results: pd.DataFrame) -> pd.Series:
|
261
|
+
"""Get the 'sub_entity' column values."""
|
186
262
|
return results[COLUMNS.ENTITY]
|
@@ -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)
|