google-meridian 1.5.0__tar.gz → 1.5.1__tar.gz
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.
- {google_meridian-1.5.0/google_meridian.egg-info → google_meridian-1.5.1}/PKG-INFO +2 -2
- {google_meridian-1.5.0 → google_meridian-1.5.1}/README.md +1 -1
- {google_meridian-1.5.0 → google_meridian-1.5.1/google_meridian.egg-info}/PKG-INFO +2 -2
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/analysis/review/checks.py +118 -116
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/analysis/review/constants.py +3 -3
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/analysis/review/results.py +131 -68
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/analysis/review/reviewer.py +4 -22
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/model/eda/eda_engine.py +1 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/version.py +1 -1
- {google_meridian-1.5.0 → google_meridian-1.5.1}/schema/serde/meridian_serde.py +6 -2
- {google_meridian-1.5.0 → google_meridian-1.5.1}/LICENSE +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/MANIFEST.in +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/google_meridian.egg-info/SOURCES.txt +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/google_meridian.egg-info/dependency_links.txt +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/google_meridian.egg-info/requires.txt +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/google_meridian.egg-info/top_level.txt +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/__init__.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/analysis/__init__.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/analysis/analyzer.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/analysis/optimizer.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/analysis/review/__init__.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/analysis/review/configs.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/analysis/summarizer.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/analysis/summary_text.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/analysis/test_utils.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/analysis/visualizer.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/backend/__init__.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/backend/config.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/backend/test_utils.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/constants.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/data/__init__.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/data/arg_builder.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/data/data_frame_input_data_builder.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/data/input_data.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/data/input_data_builder.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/data/load.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/data/nd_array_input_data_builder.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/data/test_utils.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/data/time_coordinates.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/data/validator.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/mlflow/__init__.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/mlflow/autolog.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/model/__init__.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/model/adstock_hill.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/model/context.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/model/eda/__init__.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/model/eda/constants.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/model/eda/eda_outcome.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/model/eda/eda_spec.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/model/equations.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/model/knots.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/model/media.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/model/model.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/model/model_test_data.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/model/posterior_sampler.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/model/prior_distribution.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/model/prior_sampler.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/model/spec.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/model/transformers.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/templates/card.html.jinja +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/templates/chart.html.jinja +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/templates/chips.html.jinja +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/templates/finding.html.jinja +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/templates/findings.html.jinja +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/templates/formatter.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/templates/formatter_test.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/templates/insights.html.jinja +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/templates/stats.html.jinja +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/templates/style.scss +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/templates/summary.html.jinja +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/meridian/templates/table.html.jinja +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/pyproject.toml +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/scenarioplanner/__init__.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/scenarioplanner/converters/__init__.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/scenarioplanner/converters/dataframe/__init__.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/scenarioplanner/converters/dataframe/budget_opt_converters.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/scenarioplanner/converters/dataframe/common.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/scenarioplanner/converters/dataframe/constants.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/scenarioplanner/converters/dataframe/converter.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/scenarioplanner/converters/dataframe/dataframe_model_converter.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/scenarioplanner/converters/dataframe/marketing_analyses_converters.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/scenarioplanner/converters/dataframe/rf_opt_converters.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/scenarioplanner/converters/mmm.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/scenarioplanner/converters/mmm_converter.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/scenarioplanner/converters/sheets.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/scenarioplanner/converters/test_data.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/scenarioplanner/linkingapi/__init__.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/scenarioplanner/linkingapi/constants.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/scenarioplanner/linkingapi/url_generator.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/scenarioplanner/mmm_ui_proto_generator.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/schema/__init__.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/schema/mmm_proto_generator.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/schema/model_consumer.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/schema/processors/__init__.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/schema/processors/budget_optimization_processor.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/schema/processors/common.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/schema/processors/marketing_processor.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/schema/processors/model_fit_processor.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/schema/processors/model_kernel_processor.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/schema/processors/model_processor.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/schema/processors/reach_frequency_optimization_processor.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/schema/serde/__init__.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/schema/serde/constants.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/schema/serde/distribution.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/schema/serde/eda_spec.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/schema/serde/function_registry.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/schema/serde/hyperparameters.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/schema/serde/inference_data.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/schema/serde/marketing_data.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/schema/serde/serde.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/schema/serde/test_data.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/schema/test_data.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/schema/utils/__init__.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/schema/utils/date_range_bucketing.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/schema/utils/proto_enum_converter.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/schema/utils/time_record.py +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/setup.cfg +0 -0
- {google_meridian-1.5.0 → google_meridian-1.5.1}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: google-meridian
|
|
3
|
-
Version: 1.5.
|
|
3
|
+
Version: 1.5.1
|
|
4
4
|
Summary: Google's open source mixed marketing model library, helps you understand your return on investment and direct your ad spend with confidence.
|
|
5
5
|
Author-email: The Meridian Authors <no-reply@google.com>
|
|
6
6
|
Project-URL: homepage, https://github.com/google/meridian
|
|
@@ -210,7 +210,7 @@ To cite this repository:
|
|
|
210
210
|
author = {Google Meridian Marketing Mix Modeling Team},
|
|
211
211
|
title = {Meridian: Marketing Mix Modeling},
|
|
212
212
|
url = {https://github.com/google/meridian},
|
|
213
|
-
version = {1.5.
|
|
213
|
+
version = {1.5.1},
|
|
214
214
|
year = {2025},
|
|
215
215
|
}
|
|
216
216
|
```
|
|
@@ -153,7 +153,7 @@ To cite this repository:
|
|
|
153
153
|
author = {Google Meridian Marketing Mix Modeling Team},
|
|
154
154
|
title = {Meridian: Marketing Mix Modeling},
|
|
155
155
|
url = {https://github.com/google/meridian},
|
|
156
|
-
version = {1.5.
|
|
156
|
+
version = {1.5.1},
|
|
157
157
|
year = {2025},
|
|
158
158
|
}
|
|
159
159
|
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: google-meridian
|
|
3
|
-
Version: 1.5.
|
|
3
|
+
Version: 1.5.1
|
|
4
4
|
Summary: Google's open source mixed marketing model library, helps you understand your return on investment and direct your ad spend with confidence.
|
|
5
5
|
Author-email: The Meridian Authors <no-reply@google.com>
|
|
6
6
|
Project-URL: homepage, https://github.com/google/meridian
|
|
@@ -210,7 +210,7 @@ To cite this repository:
|
|
|
210
210
|
author = {Google Meridian Marketing Mix Modeling Team},
|
|
211
211
|
title = {Meridian: Marketing Mix Modeling},
|
|
212
212
|
url = {https://github.com/google/meridian},
|
|
213
|
-
version = {1.5.
|
|
213
|
+
version = {1.5.1},
|
|
214
214
|
year = {2025},
|
|
215
215
|
}
|
|
216
216
|
```
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"""Implementation of the Model Quality Checks."""
|
|
16
16
|
|
|
17
17
|
import abc
|
|
18
|
-
from collections.abc import Sequence
|
|
18
|
+
from collections.abc import MutableMapping, Sequence
|
|
19
19
|
import dataclasses
|
|
20
20
|
from typing import Generic, TypeVar
|
|
21
21
|
import warnings
|
|
@@ -77,31 +77,16 @@ class ConvergenceCheck(
|
|
|
77
77
|
if not valid_rhat_items:
|
|
78
78
|
return results.ConvergenceCheckResult(
|
|
79
79
|
case=results.ConvergenceCases.CONVERGED,
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
review_constants.CONVERGENCE_THRESHOLD: (
|
|
84
|
-
self._config.convergence_threshold
|
|
85
|
-
),
|
|
86
|
-
},
|
|
80
|
+
config=self._config,
|
|
81
|
+
max_rhat=np.nan,
|
|
82
|
+
max_parameter=np.nan,
|
|
87
83
|
)
|
|
88
84
|
|
|
89
85
|
max_parameter, max_rhat = max(max_rhats.items(), key=lambda item: item[1])
|
|
90
86
|
|
|
91
|
-
details = {
|
|
92
|
-
review_constants.RHAT: max_rhat,
|
|
93
|
-
review_constants.PARAMETER: max_parameter,
|
|
94
|
-
review_constants.CONVERGENCE_THRESHOLD: (
|
|
95
|
-
self._config.convergence_threshold
|
|
96
|
-
),
|
|
97
|
-
}
|
|
98
|
-
|
|
99
87
|
# Case 1: Converged.
|
|
100
88
|
if max_rhat < self._config.convergence_threshold:
|
|
101
|
-
|
|
102
|
-
case=results.ConvergenceCases.CONVERGED,
|
|
103
|
-
details=details,
|
|
104
|
-
)
|
|
89
|
+
case = results.ConvergenceCases.CONVERGED
|
|
105
90
|
|
|
106
91
|
# Case 2: Not fully converged, but potentially acceptable.
|
|
107
92
|
elif (
|
|
@@ -109,17 +94,18 @@ class ConvergenceCheck(
|
|
|
109
94
|
<= max_rhat
|
|
110
95
|
< self._config.not_fully_convergence_threshold
|
|
111
96
|
):
|
|
112
|
-
|
|
113
|
-
case=results.ConvergenceCases.NOT_FULLY_CONVERGED,
|
|
114
|
-
details=details,
|
|
115
|
-
)
|
|
97
|
+
case = results.ConvergenceCases.NOT_FULLY_CONVERGED
|
|
116
98
|
|
|
117
99
|
# Case 3: Not converged and unacceptable.
|
|
118
100
|
else: # max_rhat >= divergence_threshold
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
101
|
+
case = results.ConvergenceCases.NOT_CONVERGED
|
|
102
|
+
|
|
103
|
+
return results.ConvergenceCheckResult(
|
|
104
|
+
case=case,
|
|
105
|
+
config=self._config,
|
|
106
|
+
max_rhat=max_rhat,
|
|
107
|
+
max_parameter=max_parameter,
|
|
108
|
+
)
|
|
123
109
|
|
|
124
110
|
|
|
125
111
|
# ==============================================================================
|
|
@@ -131,33 +117,25 @@ class BaselineCheck(
|
|
|
131
117
|
"""Checks for negative baseline probability."""
|
|
132
118
|
|
|
133
119
|
def run(self) -> results.BaselineCheckResult:
|
|
134
|
-
prob = self._analyzer.negative_baseline_probability()
|
|
135
|
-
|
|
136
|
-
review_constants.NEGATIVE_BASELINE_PROB: prob,
|
|
137
|
-
review_constants.NEGATIVE_BASELINE_PROB_FAIL_THRESHOLD: (
|
|
138
|
-
self._config.negative_baseline_prob_fail_threshold
|
|
139
|
-
),
|
|
140
|
-
review_constants.NEGATIVE_BASELINE_PROB_REVIEW_THRESHOLD: (
|
|
141
|
-
self._config.negative_baseline_prob_review_threshold
|
|
142
|
-
),
|
|
143
|
-
}
|
|
120
|
+
prob = float(self._analyzer.negative_baseline_probability())
|
|
121
|
+
|
|
144
122
|
# Case 1: FAIL
|
|
145
123
|
if prob > self._config.negative_baseline_prob_fail_threshold:
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
details=details,
|
|
149
|
-
)
|
|
124
|
+
case = results.BaselineCases.FAIL
|
|
125
|
+
|
|
150
126
|
# Case 2: REVIEW
|
|
151
127
|
elif prob >= self._config.negative_baseline_prob_review_threshold:
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
details=details,
|
|
155
|
-
)
|
|
128
|
+
case = results.BaselineCases.REVIEW
|
|
129
|
+
|
|
156
130
|
# Case 3: PASS
|
|
157
131
|
else:
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
132
|
+
case = results.BaselineCases.PASS
|
|
133
|
+
|
|
134
|
+
return results.BaselineCheckResult(
|
|
135
|
+
case=case,
|
|
136
|
+
config=self._config,
|
|
137
|
+
negative_baseline_prob=prob,
|
|
138
|
+
)
|
|
161
139
|
|
|
162
140
|
|
|
163
141
|
# ==============================================================================
|
|
@@ -189,45 +167,40 @@ class BayesianPPPCheck(
|
|
|
189
167
|
>= np.abs(total_outcome_actual - total_outcome_expected_mean)
|
|
190
168
|
)
|
|
191
169
|
|
|
192
|
-
details = {
|
|
193
|
-
review_constants.BAYESIAN_PPP: bayesian_ppp,
|
|
194
|
-
}
|
|
195
|
-
|
|
196
170
|
if bayesian_ppp >= self._config.ppp_threshold:
|
|
197
|
-
|
|
198
|
-
case=results.BayesianPPPCases.PASS,
|
|
199
|
-
details=details,
|
|
200
|
-
)
|
|
171
|
+
case = results.BayesianPPPCases.PASS
|
|
201
172
|
else:
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
173
|
+
case = results.BayesianPPPCases.FAIL
|
|
174
|
+
|
|
175
|
+
return results.BayesianPPPCheckResult(
|
|
176
|
+
case=case,
|
|
177
|
+
config=self._config,
|
|
178
|
+
bayesian_ppp=bayesian_ppp,
|
|
179
|
+
)
|
|
206
180
|
|
|
207
181
|
|
|
208
182
|
# ==============================================================================
|
|
209
183
|
# Check: Goodness of Fit
|
|
210
184
|
# ==============================================================================
|
|
211
|
-
def
|
|
212
|
-
|
|
185
|
+
def _set_metrics_from_gof_dataframe(
|
|
186
|
+
metrics: MutableMapping[str, float],
|
|
213
187
|
gof_df: pd.DataFrame,
|
|
214
188
|
geo_granularity: str,
|
|
215
|
-
suffix: str
|
|
189
|
+
suffix: str,
|
|
216
190
|
) -> None:
|
|
217
|
-
"""Sets the `
|
|
191
|
+
"""Sets the `metrics` variable of the GoodnessOfFitCheckResult.
|
|
218
192
|
|
|
219
193
|
This method takes a DataFrame containing goodness of fit metrics and pivots it
|
|
220
|
-
to a Series, which is then added to the `
|
|
194
|
+
to a Series, which is then added to the `metrics` variable of the
|
|
221
195
|
`GoodnessOfFitCheckResult`.
|
|
222
196
|
|
|
223
197
|
Args:
|
|
224
|
-
|
|
198
|
+
metrics: A dictionary to store the goodness of fit metrics in.
|
|
225
199
|
gof_df: A DataFrame containing predictive accuracy of the whole data (if
|
|
226
200
|
holdout set is not used) of filtered to a single evaluation set ("all",
|
|
227
201
|
"train", or "test").
|
|
228
202
|
geo_granularity: The geo granularity of the data ("geo" or "national").
|
|
229
|
-
suffix: A suffix to add to the metric names (e.g., "
|
|
230
|
-
If None, the metrics are added without a suffix.
|
|
203
|
+
suffix: A suffix to add to the metric names (e.g., "_train", "_test").
|
|
231
204
|
"""
|
|
232
205
|
gof_metrics_pivoted = gof_df.pivot(
|
|
233
206
|
index=constants.GEO_GRANULARITY,
|
|
@@ -235,22 +208,15 @@ def _set_details_from_gof_dataframe(
|
|
|
235
208
|
values=constants.VALUE,
|
|
236
209
|
)
|
|
237
210
|
gof_metrics_series = gof_metrics_pivoted.loc[geo_granularity]
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
]
|
|
248
|
-
else:
|
|
249
|
-
details[review_constants.R_SQUARED] = gof_metrics_series[
|
|
250
|
-
constants.R_SQUARED
|
|
251
|
-
]
|
|
252
|
-
details[review_constants.MAPE] = gof_metrics_series[constants.MAPE]
|
|
253
|
-
details[review_constants.WMAPE] = gof_metrics_series[constants.WMAPE]
|
|
211
|
+
metrics[f"{review_constants.R_SQUARED}{suffix}"] = gof_metrics_series[
|
|
212
|
+
constants.R_SQUARED
|
|
213
|
+
]
|
|
214
|
+
metrics[f"{review_constants.MAPE}{suffix}"] = gof_metrics_series[
|
|
215
|
+
constants.MAPE
|
|
216
|
+
]
|
|
217
|
+
metrics[f"{review_constants.WMAPE}{suffix}"] = gof_metrics_series[
|
|
218
|
+
constants.WMAPE
|
|
219
|
+
]
|
|
254
220
|
|
|
255
221
|
|
|
256
222
|
class GoodnessOfFitCheck(
|
|
@@ -269,7 +235,7 @@ class GoodnessOfFitCheck(
|
|
|
269
235
|
gof_metrics = gof_df[gof_df[constants.GEO_GRANULARITY] == geo_granularity]
|
|
270
236
|
is_holdout = constants.EVALUATION_SET_VAR in gof_df.columns
|
|
271
237
|
|
|
272
|
-
|
|
238
|
+
metrics_dict = {}
|
|
273
239
|
case = results.GoodnessOfFitCases.PASS
|
|
274
240
|
|
|
275
241
|
if is_holdout:
|
|
@@ -281,29 +247,71 @@ class GoodnessOfFitCheck(
|
|
|
281
247
|
set_metrics = gof_metrics[
|
|
282
248
|
gof_metrics[constants.EVALUATION_SET_VAR] == evaluation_set
|
|
283
249
|
]
|
|
284
|
-
|
|
285
|
-
|
|
250
|
+
_set_metrics_from_gof_dataframe(
|
|
251
|
+
metrics=metrics_dict,
|
|
286
252
|
gof_df=set_metrics,
|
|
287
253
|
geo_granularity=geo_granularity,
|
|
288
254
|
suffix=suffix,
|
|
289
255
|
)
|
|
290
|
-
if
|
|
256
|
+
if metrics_dict[f"{review_constants.R_SQUARED}{suffix}"] <= 0:
|
|
291
257
|
case = results.GoodnessOfFitCases.REVIEW
|
|
258
|
+
return results.GoodnessOfFitCheckResult(
|
|
259
|
+
case=case,
|
|
260
|
+
metrics=results.GoodnessOfFitMetrics(
|
|
261
|
+
r_squared=metrics_dict[
|
|
262
|
+
f"{review_constants.R_SQUARED}{review_constants.ALL_SUFFIX}"
|
|
263
|
+
],
|
|
264
|
+
mape=metrics_dict[
|
|
265
|
+
f"{review_constants.MAPE}{review_constants.ALL_SUFFIX}"
|
|
266
|
+
],
|
|
267
|
+
wmape=metrics_dict[
|
|
268
|
+
f"{review_constants.WMAPE}{review_constants.ALL_SUFFIX}"
|
|
269
|
+
],
|
|
270
|
+
r_squared_train=metrics_dict[
|
|
271
|
+
f"{review_constants.R_SQUARED}{review_constants.TRAIN_SUFFIX}"
|
|
272
|
+
],
|
|
273
|
+
mape_train=metrics_dict[
|
|
274
|
+
f"{review_constants.MAPE}{review_constants.TRAIN_SUFFIX}"
|
|
275
|
+
],
|
|
276
|
+
wmape_train=metrics_dict[
|
|
277
|
+
f"{review_constants.WMAPE}{review_constants.TRAIN_SUFFIX}"
|
|
278
|
+
],
|
|
279
|
+
r_squared_test=metrics_dict[
|
|
280
|
+
f"{review_constants.R_SQUARED}{review_constants.TEST_SUFFIX}"
|
|
281
|
+
],
|
|
282
|
+
mape_test=metrics_dict[
|
|
283
|
+
f"{review_constants.MAPE}{review_constants.TEST_SUFFIX}"
|
|
284
|
+
],
|
|
285
|
+
wmape_test=metrics_dict[
|
|
286
|
+
f"{review_constants.WMAPE}{review_constants.TEST_SUFFIX}"
|
|
287
|
+
],
|
|
288
|
+
),
|
|
289
|
+
is_holdout=is_holdout,
|
|
290
|
+
)
|
|
292
291
|
else:
|
|
293
|
-
|
|
294
|
-
|
|
292
|
+
_set_metrics_from_gof_dataframe(
|
|
293
|
+
metrics=metrics_dict,
|
|
295
294
|
gof_df=gof_metrics,
|
|
296
295
|
geo_granularity=geo_granularity,
|
|
297
|
-
suffix=
|
|
296
|
+
suffix=review_constants.ALL_SUFFIX,
|
|
298
297
|
)
|
|
299
|
-
if
|
|
298
|
+
if metrics_dict[review_constants.R_SQUARED] <= 0:
|
|
300
299
|
case = results.GoodnessOfFitCases.REVIEW
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
300
|
+
return results.GoodnessOfFitCheckResult(
|
|
301
|
+
case=case,
|
|
302
|
+
metrics=results.GoodnessOfFitMetrics(
|
|
303
|
+
r_squared=metrics_dict[
|
|
304
|
+
f"{review_constants.R_SQUARED}{review_constants.ALL_SUFFIX}"
|
|
305
|
+
],
|
|
306
|
+
mape=metrics_dict[
|
|
307
|
+
f"{review_constants.MAPE}{review_constants.ALL_SUFFIX}"
|
|
308
|
+
],
|
|
309
|
+
wmape=metrics_dict[
|
|
310
|
+
f"{review_constants.WMAPE}{review_constants.ALL_SUFFIX}"
|
|
311
|
+
],
|
|
312
|
+
),
|
|
313
|
+
is_holdout=is_holdout,
|
|
314
|
+
)
|
|
307
315
|
|
|
308
316
|
|
|
309
317
|
# ==============================================================================
|
|
@@ -475,8 +483,10 @@ def _compute_channel_results(
|
|
|
475
483
|
channel_results.append(
|
|
476
484
|
results.ROIConsistencyChannelResult(
|
|
477
485
|
case=case,
|
|
478
|
-
details={},
|
|
479
486
|
channel_name=channel,
|
|
487
|
+
prior_roi_lo=np.nan,
|
|
488
|
+
prior_roi_hi=np.nan,
|
|
489
|
+
posterior_roi_mean=np.nan,
|
|
480
490
|
)
|
|
481
491
|
)
|
|
482
492
|
for i, channel in enumerate(channel_data.all_channels):
|
|
@@ -491,14 +501,10 @@ def _compute_channel_results(
|
|
|
491
501
|
channel_results.append(
|
|
492
502
|
results.ROIConsistencyChannelResult(
|
|
493
503
|
case=case,
|
|
494
|
-
details={
|
|
495
|
-
review_constants.PRIOR_ROI_LO: channel_data.prior_roi_los[i],
|
|
496
|
-
review_constants.PRIOR_ROI_HI: channel_data.prior_roi_his[i],
|
|
497
|
-
review_constants.POSTERIOR_ROI_MEAN: (
|
|
498
|
-
channel_data.posterior_means[i]
|
|
499
|
-
),
|
|
500
|
-
},
|
|
501
504
|
channel_name=channel,
|
|
505
|
+
prior_roi_lo=channel_data.prior_roi_los[i],
|
|
506
|
+
prior_roi_hi=channel_data.prior_roi_his[i],
|
|
507
|
+
posterior_roi_mean=channel_data.posterior_means[i],
|
|
502
508
|
)
|
|
503
509
|
)
|
|
504
510
|
return channel_results
|
|
@@ -558,7 +564,7 @@ def _compute_aggregate_result(
|
|
|
558
564
|
|
|
559
565
|
return results.ROIConsistencyCheckResult(
|
|
560
566
|
case=aggregate_case,
|
|
561
|
-
|
|
567
|
+
aggregate_details=aggregate_details,
|
|
562
568
|
channel_results=channel_results,
|
|
563
569
|
)
|
|
564
570
|
|
|
@@ -734,7 +740,7 @@ class PriorPosteriorShiftCheck(
|
|
|
734
740
|
no_shift_channels.append(channel_name)
|
|
735
741
|
channel_results.append(
|
|
736
742
|
results.PriorPosteriorShiftChannelResult(
|
|
737
|
-
case=case,
|
|
743
|
+
case=case, channel_name=channel_name
|
|
738
744
|
)
|
|
739
745
|
)
|
|
740
746
|
return channel_results, no_shift_channels
|
|
@@ -752,17 +758,13 @@ class PriorPosteriorShiftCheck(
|
|
|
752
758
|
|
|
753
759
|
if no_shift_channels:
|
|
754
760
|
agg_case = results.PriorPosteriorShiftAggregateCases.REVIEW
|
|
755
|
-
final_details = {
|
|
756
|
-
"channels_str": ", ".join(
|
|
757
|
-
f"`{channel}`" for channel in no_shift_channels
|
|
758
|
-
)
|
|
759
|
-
}
|
|
760
761
|
else:
|
|
761
762
|
agg_case = results.PriorPosteriorShiftAggregateCases.PASS
|
|
762
|
-
final_details = {}
|
|
763
763
|
|
|
764
764
|
return results.PriorPosteriorShiftCheckResult(
|
|
765
|
-
case=agg_case,
|
|
765
|
+
case=agg_case,
|
|
766
|
+
channel_results=channel_results,
|
|
767
|
+
no_shift_channels=no_shift_channels,
|
|
766
768
|
)
|
|
767
769
|
|
|
768
770
|
def run(self) -> results.PriorPosteriorShiftCheckResult:
|
|
@@ -32,9 +32,9 @@ NEGATIVE_BASELINE_PROB_REVIEW_THRESHOLD = (
|
|
|
32
32
|
R_SQUARED = "r_squared"
|
|
33
33
|
MAPE = "mape"
|
|
34
34
|
WMAPE = "wmape"
|
|
35
|
-
ALL_SUFFIX = "
|
|
36
|
-
TRAIN_SUFFIX = "
|
|
37
|
-
TEST_SUFFIX = "
|
|
35
|
+
ALL_SUFFIX = ""
|
|
36
|
+
TRAIN_SUFFIX = "_train"
|
|
37
|
+
TEST_SUFFIX = "_test"
|
|
38
38
|
EVALUATION_SET_SUFFIXES = (ALL_SUFFIX, TRAIN_SUFFIX, TEST_SUFFIX)
|
|
39
39
|
MEAN = "mean"
|
|
40
40
|
VARIANCE = "variance"
|