google-meridian 1.3.1__tar.gz → 1.4.0__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.4.0/MANIFEST.in +2 -0
- {google_meridian-1.3.1/google_meridian.egg-info → google_meridian-1.4.0}/PKG-INFO +13 -9
- {google_meridian-1.3.1 → google_meridian-1.4.0}/README.md +1 -1
- {google_meridian-1.3.1 → google_meridian-1.4.0/google_meridian.egg-info}/PKG-INFO +13 -9
- {google_meridian-1.3.1 → google_meridian-1.4.0}/google_meridian.egg-info/SOURCES.txt +42 -10
- {google_meridian-1.3.1 → google_meridian-1.4.0}/google_meridian.egg-info/requires.txt +12 -7
- {google_meridian-1.3.1 → google_meridian-1.4.0}/google_meridian.egg-info/top_level.txt +1 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/analysis/__init__.py +1 -2
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/analysis/analyzer.py +0 -1
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/analysis/optimizer.py +5 -3
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/analysis/review/checks.py +81 -30
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/analysis/review/constants.py +4 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/analysis/review/results.py +40 -9
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/analysis/summarizer.py +8 -3
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/analysis/test_utils.py +934 -485
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/analysis/visualizer.py +11 -7
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/backend/__init__.py +53 -5
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/backend/test_utils.py +72 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/constants.py +2 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/data/load.py +2 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/data/test_utils.py +82 -10
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/model/__init__.py +2 -0
- google_meridian-1.4.0/meridian/model/context.py +925 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/model/eda/__init__.py +0 -1
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/model/eda/constants.py +13 -2
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/model/eda/eda_engine.py +299 -37
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/model/eda/eda_outcome.py +21 -1
- google_meridian-1.4.0/meridian/model/equations.py +418 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/model/knots.py +75 -47
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/model/model.py +93 -792
- {google_meridian-1.3.1/meridian/analysis → google_meridian-1.4.0/meridian}/templates/card.html.jinja +1 -1
- {google_meridian-1.3.1/meridian/analysis → google_meridian-1.4.0/meridian}/templates/chart.html.jinja +1 -1
- {google_meridian-1.3.1/meridian/analysis → google_meridian-1.4.0/meridian}/templates/chips.html.jinja +1 -1
- {google_meridian-1.3.1/meridian/analysis → google_meridian-1.4.0/meridian/templates}/formatter.py +12 -1
- google_meridian-1.4.0/meridian/templates/formatter_test.py +216 -0
- {google_meridian-1.3.1/meridian/analysis → google_meridian-1.4.0/meridian}/templates/insights.html.jinja +1 -1
- {google_meridian-1.3.1/meridian/analysis → google_meridian-1.4.0/meridian}/templates/stats.html.jinja +1 -1
- {google_meridian-1.3.1/meridian/analysis → google_meridian-1.4.0/meridian}/templates/style.scss +1 -1
- {google_meridian-1.3.1/meridian/analysis → google_meridian-1.4.0/meridian}/templates/summary.html.jinja +4 -2
- {google_meridian-1.3.1/meridian/analysis → google_meridian-1.4.0/meridian}/templates/table.html.jinja +1 -1
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/version.py +1 -1
- {google_meridian-1.3.1 → google_meridian-1.4.0}/pyproject.toml +15 -8
- google_meridian-1.4.0/scenarioplanner/__init__.py +42 -0
- google_meridian-1.4.0/scenarioplanner/converters/__init__.py +25 -0
- google_meridian-1.4.0/scenarioplanner/converters/dataframe/__init__.py +28 -0
- google_meridian-1.4.0/scenarioplanner/converters/dataframe/budget_opt_converters.py +383 -0
- google_meridian-1.4.0/scenarioplanner/converters/dataframe/common.py +71 -0
- google_meridian-1.4.0/scenarioplanner/converters/dataframe/constants.py +137 -0
- google_meridian-1.4.0/scenarioplanner/converters/dataframe/converter.py +42 -0
- google_meridian-1.4.0/scenarioplanner/converters/dataframe/dataframe_model_converter.py +70 -0
- google_meridian-1.4.0/scenarioplanner/converters/dataframe/marketing_analyses_converters.py +543 -0
- google_meridian-1.4.0/scenarioplanner/converters/dataframe/rf_opt_converters.py +314 -0
- google_meridian-1.4.0/scenarioplanner/converters/mmm.py +743 -0
- google_meridian-1.4.0/scenarioplanner/converters/mmm_converter.py +58 -0
- google_meridian-1.4.0/scenarioplanner/converters/sheets.py +156 -0
- google_meridian-1.4.0/scenarioplanner/converters/test_data.py +714 -0
- google_meridian-1.4.0/scenarioplanner/linkingapi/__init__.py +47 -0
- google_meridian-1.4.0/scenarioplanner/linkingapi/constants.py +27 -0
- google_meridian-1.4.0/scenarioplanner/linkingapi/url_generator.py +131 -0
- google_meridian-1.4.0/scenarioplanner/mmm_ui_proto_generator.py +354 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/schema/__init__.py +15 -0
- google_meridian-1.4.0/schema/mmm_proto_generator.py +71 -0
- google_meridian-1.4.0/schema/model_consumer.py +133 -0
- google_meridian-1.4.0/schema/processors/__init__.py +77 -0
- google_meridian-1.4.0/schema/processors/budget_optimization_processor.py +832 -0
- google_meridian-1.4.0/schema/processors/common.py +64 -0
- google_meridian-1.4.0/schema/processors/marketing_processor.py +1136 -0
- google_meridian-1.4.0/schema/processors/model_fit_processor.py +367 -0
- google_meridian-1.4.0/schema/processors/model_kernel_processor.py +117 -0
- google_meridian-1.4.0/schema/processors/model_processor.py +412 -0
- google_meridian-1.4.0/schema/processors/reach_frequency_optimization_processor.py +584 -0
- google_meridian-1.4.0/schema/test_data.py +380 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/schema/utils/__init__.py +1 -0
- google_meridian-1.4.0/schema/utils/date_range_bucketing.py +117 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/setup.py +1 -1
- google_meridian-1.3.1/MANIFEST.in +0 -2
- google_meridian-1.3.1/meridian/model/eda/meridian_eda.py +0 -220
- {google_meridian-1.3.1 → google_meridian-1.4.0}/LICENSE +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/google_meridian.egg-info/dependency_links.txt +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/__init__.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/analysis/review/__init__.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/analysis/review/configs.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/analysis/review/reviewer.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/analysis/summary_text.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/backend/config.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/data/__init__.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/data/arg_builder.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/data/data_frame_input_data_builder.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/data/input_data.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/data/input_data_builder.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/data/nd_array_input_data_builder.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/data/time_coordinates.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/mlflow/__init__.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/mlflow/autolog.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/model/adstock_hill.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/model/eda/eda_spec.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/model/media.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/model/model_test_data.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/model/posterior_sampler.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/model/prior_distribution.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/model/prior_sampler.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/model/spec.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/meridian/model/transformers.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/schema/serde/__init__.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/schema/serde/constants.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/schema/serde/distribution.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/schema/serde/eda_spec.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/schema/serde/function_registry.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/schema/serde/hyperparameters.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/schema/serde/inference_data.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/schema/serde/marketing_data.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/schema/serde/meridian_serde.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/schema/serde/serde.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/schema/serde/test_data.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/schema/utils/time_record.py +0 -0
- {google_meridian-1.3.1 → google_meridian-1.4.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: google-meridian
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.0
|
|
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
|
|
@@ -22,12 +22,11 @@ Requires-Dist: joblib
|
|
|
22
22
|
Requires-Dist: natsort<8,>=7.1.1
|
|
23
23
|
Requires-Dist: numpy<3,>=2.0.2
|
|
24
24
|
Requires-Dist: pandas<3,>=2.2.2
|
|
25
|
-
Requires-Dist: patsy<1,>=0.5.3
|
|
26
25
|
Requires-Dist: scipy<2,>=1.13.1
|
|
27
26
|
Requires-Dist: statsmodels>=0.14.5
|
|
28
|
-
Requires-Dist: tensorflow<2.
|
|
27
|
+
Requires-Dist: tensorflow<2.21,>=2.18
|
|
29
28
|
Requires-Dist: tensorflow-probability<0.26,>=0.25
|
|
30
|
-
Requires-Dist: tf-keras<2.
|
|
29
|
+
Requires-Dist: tf-keras<2.21,>=2.18
|
|
31
30
|
Requires-Dist: xarray
|
|
32
31
|
Provides-Extra: dev
|
|
33
32
|
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
@@ -38,16 +37,21 @@ Provides-Extra: colab
|
|
|
38
37
|
Requires-Dist: psutil; extra == "colab"
|
|
39
38
|
Requires-Dist: python-calamine; extra == "colab"
|
|
40
39
|
Provides-Extra: and-cuda
|
|
41
|
-
Requires-Dist: tensorflow[and-cuda]<2.
|
|
40
|
+
Requires-Dist: tensorflow[and-cuda]<2.21,>=2.18; extra == "and-cuda"
|
|
42
41
|
Provides-Extra: mlflow
|
|
43
42
|
Requires-Dist: mlflow; extra == "mlflow"
|
|
44
43
|
Provides-Extra: jax
|
|
45
|
-
Requires-Dist: jax==0.
|
|
46
|
-
Requires-Dist: jaxlib==0.
|
|
44
|
+
Requires-Dist: jax==0.5.3; extra == "jax"
|
|
45
|
+
Requires-Dist: jaxlib==0.5.3; extra == "jax"
|
|
47
46
|
Requires-Dist: tensorflow-probability[substrates-jax]==0.25.0; extra == "jax"
|
|
48
47
|
Provides-Extra: schema
|
|
49
|
-
Requires-Dist: mmm-proto-schema; extra == "schema"
|
|
48
|
+
Requires-Dist: mmm-proto-schema>=1.1.0; extra == "schema"
|
|
50
49
|
Requires-Dist: semver; extra == "schema"
|
|
50
|
+
Provides-Extra: scenarioplanner
|
|
51
|
+
Requires-Dist: google-api-python-client; extra == "scenarioplanner"
|
|
52
|
+
Requires-Dist: google-auth; extra == "scenarioplanner"
|
|
53
|
+
Requires-Dist: mmm-proto-schema>=1.1.0; extra == "scenarioplanner"
|
|
54
|
+
Requires-Dist: semver; extra == "scenarioplanner"
|
|
51
55
|
Dynamic: license-file
|
|
52
56
|
|
|
53
57
|
# About Meridian
|
|
@@ -203,7 +207,7 @@ To cite this repository:
|
|
|
203
207
|
author = {Google Meridian Marketing Mix Modeling Team},
|
|
204
208
|
title = {Meridian: Marketing Mix Modeling},
|
|
205
209
|
url = {https://github.com/google/meridian},
|
|
206
|
-
version = {1.
|
|
210
|
+
version = {1.4.0},
|
|
207
211
|
year = {2025},
|
|
208
212
|
}
|
|
209
213
|
```
|
|
@@ -151,7 +151,7 @@ To cite this repository:
|
|
|
151
151
|
author = {Google Meridian Marketing Mix Modeling Team},
|
|
152
152
|
title = {Meridian: Marketing Mix Modeling},
|
|
153
153
|
url = {https://github.com/google/meridian},
|
|
154
|
-
version = {1.
|
|
154
|
+
version = {1.4.0},
|
|
155
155
|
year = {2025},
|
|
156
156
|
}
|
|
157
157
|
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: google-meridian
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.0
|
|
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
|
|
@@ -22,12 +22,11 @@ Requires-Dist: joblib
|
|
|
22
22
|
Requires-Dist: natsort<8,>=7.1.1
|
|
23
23
|
Requires-Dist: numpy<3,>=2.0.2
|
|
24
24
|
Requires-Dist: pandas<3,>=2.2.2
|
|
25
|
-
Requires-Dist: patsy<1,>=0.5.3
|
|
26
25
|
Requires-Dist: scipy<2,>=1.13.1
|
|
27
26
|
Requires-Dist: statsmodels>=0.14.5
|
|
28
|
-
Requires-Dist: tensorflow<2.
|
|
27
|
+
Requires-Dist: tensorflow<2.21,>=2.18
|
|
29
28
|
Requires-Dist: tensorflow-probability<0.26,>=0.25
|
|
30
|
-
Requires-Dist: tf-keras<2.
|
|
29
|
+
Requires-Dist: tf-keras<2.21,>=2.18
|
|
31
30
|
Requires-Dist: xarray
|
|
32
31
|
Provides-Extra: dev
|
|
33
32
|
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
@@ -38,16 +37,21 @@ Provides-Extra: colab
|
|
|
38
37
|
Requires-Dist: psutil; extra == "colab"
|
|
39
38
|
Requires-Dist: python-calamine; extra == "colab"
|
|
40
39
|
Provides-Extra: and-cuda
|
|
41
|
-
Requires-Dist: tensorflow[and-cuda]<2.
|
|
40
|
+
Requires-Dist: tensorflow[and-cuda]<2.21,>=2.18; extra == "and-cuda"
|
|
42
41
|
Provides-Extra: mlflow
|
|
43
42
|
Requires-Dist: mlflow; extra == "mlflow"
|
|
44
43
|
Provides-Extra: jax
|
|
45
|
-
Requires-Dist: jax==0.
|
|
46
|
-
Requires-Dist: jaxlib==0.
|
|
44
|
+
Requires-Dist: jax==0.5.3; extra == "jax"
|
|
45
|
+
Requires-Dist: jaxlib==0.5.3; extra == "jax"
|
|
47
46
|
Requires-Dist: tensorflow-probability[substrates-jax]==0.25.0; extra == "jax"
|
|
48
47
|
Provides-Extra: schema
|
|
49
|
-
Requires-Dist: mmm-proto-schema; extra == "schema"
|
|
48
|
+
Requires-Dist: mmm-proto-schema>=1.1.0; extra == "schema"
|
|
50
49
|
Requires-Dist: semver; extra == "schema"
|
|
50
|
+
Provides-Extra: scenarioplanner
|
|
51
|
+
Requires-Dist: google-api-python-client; extra == "scenarioplanner"
|
|
52
|
+
Requires-Dist: google-auth; extra == "scenarioplanner"
|
|
53
|
+
Requires-Dist: mmm-proto-schema>=1.1.0; extra == "scenarioplanner"
|
|
54
|
+
Requires-Dist: semver; extra == "scenarioplanner"
|
|
51
55
|
Dynamic: license-file
|
|
52
56
|
|
|
53
57
|
# About Meridian
|
|
@@ -203,7 +207,7 @@ To cite this repository:
|
|
|
203
207
|
author = {Google Meridian Marketing Mix Modeling Team},
|
|
204
208
|
title = {Meridian: Marketing Mix Modeling},
|
|
205
209
|
url = {https://github.com/google/meridian},
|
|
206
|
-
version = {1.
|
|
210
|
+
version = {1.4.0},
|
|
207
211
|
year = {2025},
|
|
208
212
|
}
|
|
209
213
|
```
|
|
@@ -13,7 +13,6 @@ meridian/constants.py
|
|
|
13
13
|
meridian/version.py
|
|
14
14
|
meridian/analysis/__init__.py
|
|
15
15
|
meridian/analysis/analyzer.py
|
|
16
|
-
meridian/analysis/formatter.py
|
|
17
16
|
meridian/analysis/optimizer.py
|
|
18
17
|
meridian/analysis/summarizer.py
|
|
19
18
|
meridian/analysis/summary_text.py
|
|
@@ -25,14 +24,6 @@ meridian/analysis/review/configs.py
|
|
|
25
24
|
meridian/analysis/review/constants.py
|
|
26
25
|
meridian/analysis/review/results.py
|
|
27
26
|
meridian/analysis/review/reviewer.py
|
|
28
|
-
meridian/analysis/templates/card.html.jinja
|
|
29
|
-
meridian/analysis/templates/chart.html.jinja
|
|
30
|
-
meridian/analysis/templates/chips.html.jinja
|
|
31
|
-
meridian/analysis/templates/insights.html.jinja
|
|
32
|
-
meridian/analysis/templates/stats.html.jinja
|
|
33
|
-
meridian/analysis/templates/style.scss
|
|
34
|
-
meridian/analysis/templates/summary.html.jinja
|
|
35
|
-
meridian/analysis/templates/table.html.jinja
|
|
36
27
|
meridian/backend/__init__.py
|
|
37
28
|
meridian/backend/config.py
|
|
38
29
|
meridian/backend/test_utils.py
|
|
@@ -49,6 +40,8 @@ meridian/mlflow/__init__.py
|
|
|
49
40
|
meridian/mlflow/autolog.py
|
|
50
41
|
meridian/model/__init__.py
|
|
51
42
|
meridian/model/adstock_hill.py
|
|
43
|
+
meridian/model/context.py
|
|
44
|
+
meridian/model/equations.py
|
|
52
45
|
meridian/model/knots.py
|
|
53
46
|
meridian/model/media.py
|
|
54
47
|
meridian/model/model.py
|
|
@@ -63,8 +56,46 @@ meridian/model/eda/constants.py
|
|
|
63
56
|
meridian/model/eda/eda_engine.py
|
|
64
57
|
meridian/model/eda/eda_outcome.py
|
|
65
58
|
meridian/model/eda/eda_spec.py
|
|
66
|
-
meridian/
|
|
59
|
+
meridian/templates/card.html.jinja
|
|
60
|
+
meridian/templates/chart.html.jinja
|
|
61
|
+
meridian/templates/chips.html.jinja
|
|
62
|
+
meridian/templates/formatter.py
|
|
63
|
+
meridian/templates/formatter_test.py
|
|
64
|
+
meridian/templates/insights.html.jinja
|
|
65
|
+
meridian/templates/stats.html.jinja
|
|
66
|
+
meridian/templates/style.scss
|
|
67
|
+
meridian/templates/summary.html.jinja
|
|
68
|
+
meridian/templates/table.html.jinja
|
|
69
|
+
scenarioplanner/__init__.py
|
|
70
|
+
scenarioplanner/mmm_ui_proto_generator.py
|
|
71
|
+
scenarioplanner/converters/__init__.py
|
|
72
|
+
scenarioplanner/converters/mmm.py
|
|
73
|
+
scenarioplanner/converters/mmm_converter.py
|
|
74
|
+
scenarioplanner/converters/sheets.py
|
|
75
|
+
scenarioplanner/converters/test_data.py
|
|
76
|
+
scenarioplanner/converters/dataframe/__init__.py
|
|
77
|
+
scenarioplanner/converters/dataframe/budget_opt_converters.py
|
|
78
|
+
scenarioplanner/converters/dataframe/common.py
|
|
79
|
+
scenarioplanner/converters/dataframe/constants.py
|
|
80
|
+
scenarioplanner/converters/dataframe/converter.py
|
|
81
|
+
scenarioplanner/converters/dataframe/dataframe_model_converter.py
|
|
82
|
+
scenarioplanner/converters/dataframe/marketing_analyses_converters.py
|
|
83
|
+
scenarioplanner/converters/dataframe/rf_opt_converters.py
|
|
84
|
+
scenarioplanner/linkingapi/__init__.py
|
|
85
|
+
scenarioplanner/linkingapi/constants.py
|
|
86
|
+
scenarioplanner/linkingapi/url_generator.py
|
|
67
87
|
schema/__init__.py
|
|
88
|
+
schema/mmm_proto_generator.py
|
|
89
|
+
schema/model_consumer.py
|
|
90
|
+
schema/test_data.py
|
|
91
|
+
schema/processors/__init__.py
|
|
92
|
+
schema/processors/budget_optimization_processor.py
|
|
93
|
+
schema/processors/common.py
|
|
94
|
+
schema/processors/marketing_processor.py
|
|
95
|
+
schema/processors/model_fit_processor.py
|
|
96
|
+
schema/processors/model_kernel_processor.py
|
|
97
|
+
schema/processors/model_processor.py
|
|
98
|
+
schema/processors/reach_frequency_optimization_processor.py
|
|
68
99
|
schema/serde/__init__.py
|
|
69
100
|
schema/serde/constants.py
|
|
70
101
|
schema/serde/distribution.py
|
|
@@ -77,4 +108,5 @@ schema/serde/meridian_serde.py
|
|
|
77
108
|
schema/serde/serde.py
|
|
78
109
|
schema/serde/test_data.py
|
|
79
110
|
schema/utils/__init__.py
|
|
111
|
+
schema/utils/date_range_bucketing.py
|
|
80
112
|
schema/utils/time_record.py
|
|
@@ -5,16 +5,15 @@ joblib
|
|
|
5
5
|
natsort<8,>=7.1.1
|
|
6
6
|
numpy<3,>=2.0.2
|
|
7
7
|
pandas<3,>=2.2.2
|
|
8
|
-
patsy<1,>=0.5.3
|
|
9
8
|
scipy<2,>=1.13.1
|
|
10
9
|
statsmodels>=0.14.5
|
|
11
|
-
tensorflow<2.
|
|
10
|
+
tensorflow<2.21,>=2.18
|
|
12
11
|
tensorflow-probability<0.26,>=0.25
|
|
13
|
-
tf-keras<2.
|
|
12
|
+
tf-keras<2.21,>=2.18
|
|
14
13
|
xarray
|
|
15
14
|
|
|
16
15
|
[and-cuda]
|
|
17
|
-
tensorflow[and-cuda]<2.
|
|
16
|
+
tensorflow[and-cuda]<2.21,>=2.18
|
|
18
17
|
|
|
19
18
|
[colab]
|
|
20
19
|
psutil
|
|
@@ -27,13 +26,19 @@ pylint>=2.6.0
|
|
|
27
26
|
pyink
|
|
28
27
|
|
|
29
28
|
[jax]
|
|
30
|
-
jax==0.
|
|
31
|
-
jaxlib==0.
|
|
29
|
+
jax==0.5.3
|
|
30
|
+
jaxlib==0.5.3
|
|
32
31
|
tensorflow-probability[substrates-jax]==0.25.0
|
|
33
32
|
|
|
34
33
|
[mlflow]
|
|
35
34
|
mlflow
|
|
36
35
|
|
|
36
|
+
[scenarioplanner]
|
|
37
|
+
google-api-python-client
|
|
38
|
+
google-auth
|
|
39
|
+
mmm-proto-schema>=1.1.0
|
|
40
|
+
semver
|
|
41
|
+
|
|
37
42
|
[schema]
|
|
38
|
-
mmm-proto-schema
|
|
43
|
+
mmm-proto-schema>=1.1.0
|
|
39
44
|
semver
|
|
@@ -15,9 +15,8 @@
|
|
|
15
15
|
"""Meridian analysis API for trained models."""
|
|
16
16
|
|
|
17
17
|
from meridian.analysis import analyzer
|
|
18
|
-
from meridian.analysis import formatter
|
|
19
18
|
from meridian.analysis import optimizer
|
|
20
19
|
from meridian.analysis import review
|
|
21
20
|
from meridian.analysis import summarizer
|
|
22
21
|
from meridian.analysis import visualizer
|
|
23
|
-
|
|
22
|
+
from meridian.templates import formatter
|
|
@@ -53,7 +53,6 @@ def _validate_non_media_baseline_values_numbers(
|
|
|
53
53
|
)
|
|
54
54
|
|
|
55
55
|
|
|
56
|
-
# TODO: Refactor the related unit tests to be under DataTensors.
|
|
57
56
|
@dataclasses.dataclass
|
|
58
57
|
class DataTensors(backend.ExtensionType):
|
|
59
58
|
"""Container for data variable arguments of Analyzer methods.
|
|
@@ -27,10 +27,10 @@ import jinja2
|
|
|
27
27
|
from meridian import backend
|
|
28
28
|
from meridian import constants as c
|
|
29
29
|
from meridian.analysis import analyzer as analyzer_module
|
|
30
|
-
from meridian.analysis import formatter
|
|
31
30
|
from meridian.analysis import summary_text
|
|
32
31
|
from meridian.data import time_coordinates as tc
|
|
33
32
|
from meridian.model import model
|
|
33
|
+
from meridian.templates import formatter
|
|
34
34
|
import numpy as np
|
|
35
35
|
import pandas as pd
|
|
36
36
|
import xarray as xr
|
|
@@ -1174,10 +1174,12 @@ class OptimizationResults:
|
|
|
1174
1174
|
diff = self.optimized_data.total_cpik - self.nonoptimized_data.total_cpik
|
|
1175
1175
|
non_optimized_performance_title = summary_text.NON_OPTIMIZED_CPIK_LABEL
|
|
1176
1176
|
non_optimized_performance_stat = (
|
|
1177
|
-
f'
|
|
1177
|
+
f'{currency}{self.nonoptimized_data.total_cpik:.2f}'
|
|
1178
1178
|
)
|
|
1179
1179
|
optimized_performance_title = summary_text.OPTIMIZED_CPIK_LABEL
|
|
1180
|
-
optimized_performance_stat =
|
|
1180
|
+
optimized_performance_stat = (
|
|
1181
|
+
f'{currency}{self.optimized_data.total_cpik:.2f}'
|
|
1182
|
+
)
|
|
1181
1183
|
optimized_performance_diff = formatter.compact_number(diff, 2, currency)
|
|
1182
1184
|
non_optimized_performance = formatter.StatsSpec(
|
|
1183
1185
|
title=non_optimized_performance_title,
|
|
@@ -28,6 +28,7 @@ from meridian.analysis.review import constants as review_constants
|
|
|
28
28
|
from meridian.analysis.review import results
|
|
29
29
|
from meridian.model import model
|
|
30
30
|
import numpy as np
|
|
31
|
+
import pandas as pd
|
|
31
32
|
|
|
32
33
|
ConfigType = TypeVar("ConfigType", bound=configs.BaseConfig)
|
|
33
34
|
ResultType = TypeVar("ResultType", bound=results.CheckResult)
|
|
@@ -207,6 +208,51 @@ class BayesianPPPCheck(
|
|
|
207
208
|
# ==============================================================================
|
|
208
209
|
# Check: Goodness of Fit
|
|
209
210
|
# ==============================================================================
|
|
211
|
+
def _set_details_from_gof_dataframe(
|
|
212
|
+
details: dict[str, float],
|
|
213
|
+
gof_df: pd.DataFrame,
|
|
214
|
+
geo_granularity: str,
|
|
215
|
+
suffix: str | None = None,
|
|
216
|
+
) -> None:
|
|
217
|
+
"""Sets the `details` variable of the GoodnessOfFitCheckResult.
|
|
218
|
+
|
|
219
|
+
This method takes a DataFrame containing goodness of fit metrics and pivots it
|
|
220
|
+
to a Series, which is then added to the `details` variable of the
|
|
221
|
+
`GoodnessOfFitCheckResult`.
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
details: A dictionary to store the goodness of fit metrics in.
|
|
225
|
+
gof_df: A DataFrame containing predictive accuracy of the whole data (if
|
|
226
|
+
holdout set is not used) of filtered to a single evaluation set ("all",
|
|
227
|
+
"train", or "test").
|
|
228
|
+
geo_granularity: The geo granularity of the data ("geo" or "national").
|
|
229
|
+
suffix: A suffix to add to the metric names (e.g., "all", "train", "test").
|
|
230
|
+
If None, the metrics are added without a suffix.
|
|
231
|
+
"""
|
|
232
|
+
gof_metrics_pivoted = gof_df.pivot(
|
|
233
|
+
index=constants.GEO_GRANULARITY,
|
|
234
|
+
columns=constants.METRIC,
|
|
235
|
+
values=constants.VALUE,
|
|
236
|
+
)
|
|
237
|
+
gof_metrics_series = gof_metrics_pivoted.loc[geo_granularity]
|
|
238
|
+
if suffix is not None:
|
|
239
|
+
details[f"{review_constants.R_SQUARED}_{suffix}"] = gof_metrics_series[
|
|
240
|
+
constants.R_SQUARED
|
|
241
|
+
]
|
|
242
|
+
details[f"{review_constants.MAPE}_{suffix}"] = gof_metrics_series[
|
|
243
|
+
constants.MAPE
|
|
244
|
+
]
|
|
245
|
+
details[f"{review_constants.WMAPE}_{suffix}"] = gof_metrics_series[
|
|
246
|
+
constants.WMAPE
|
|
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]
|
|
254
|
+
|
|
255
|
+
|
|
210
256
|
class GoodnessOfFitCheck(
|
|
211
257
|
BaseCheck[configs.GoodnessOfFitConfig, results.GoodnessOfFitCheckResult]
|
|
212
258
|
):
|
|
@@ -221,38 +267,43 @@ class GoodnessOfFitCheck(
|
|
|
221
267
|
)
|
|
222
268
|
|
|
223
269
|
gof_metrics = gof_df[gof_df[constants.GEO_GRANULARITY] == geo_granularity]
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
case=results.GoodnessOfFitCases.PASS,
|
|
249
|
-
details=details,
|
|
250
|
-
)
|
|
251
|
-
else: # r_squared <= 0
|
|
252
|
-
return results.GoodnessOfFitCheckResult(
|
|
253
|
-
case=results.GoodnessOfFitCases.REVIEW,
|
|
270
|
+
is_holdout = constants.EVALUATION_SET_VAR in gof_df.columns
|
|
271
|
+
|
|
272
|
+
details = {}
|
|
273
|
+
case = results.GoodnessOfFitCases.PASS
|
|
274
|
+
|
|
275
|
+
if is_holdout:
|
|
276
|
+
for evaluation_set, suffix in [
|
|
277
|
+
(constants.ALL_DATA, review_constants.ALL_SUFFIX),
|
|
278
|
+
(constants.TRAIN, review_constants.TRAIN_SUFFIX),
|
|
279
|
+
(constants.TEST, review_constants.TEST_SUFFIX),
|
|
280
|
+
]:
|
|
281
|
+
set_metrics = gof_metrics[
|
|
282
|
+
gof_metrics[constants.EVALUATION_SET_VAR] == evaluation_set
|
|
283
|
+
]
|
|
284
|
+
_set_details_from_gof_dataframe(
|
|
285
|
+
details=details,
|
|
286
|
+
gof_df=set_metrics,
|
|
287
|
+
geo_granularity=geo_granularity,
|
|
288
|
+
suffix=suffix,
|
|
289
|
+
)
|
|
290
|
+
if details[f"{review_constants.R_SQUARED}_{suffix}"] <= 0:
|
|
291
|
+
case = results.GoodnessOfFitCases.REVIEW
|
|
292
|
+
else:
|
|
293
|
+
_set_details_from_gof_dataframe(
|
|
254
294
|
details=details,
|
|
295
|
+
gof_df=gof_metrics,
|
|
296
|
+
geo_granularity=geo_granularity,
|
|
297
|
+
suffix=None,
|
|
255
298
|
)
|
|
299
|
+
if details[review_constants.R_SQUARED] <= 0:
|
|
300
|
+
case = results.GoodnessOfFitCases.REVIEW
|
|
301
|
+
|
|
302
|
+
return results.GoodnessOfFitCheckResult(
|
|
303
|
+
case=case,
|
|
304
|
+
details=details,
|
|
305
|
+
is_holdout=is_holdout,
|
|
306
|
+
)
|
|
256
307
|
|
|
257
308
|
|
|
258
309
|
# ==============================================================================
|
|
@@ -32,6 +32,10 @@ NEGATIVE_BASELINE_PROB_REVIEW_THRESHOLD = (
|
|
|
32
32
|
R_SQUARED = "r_squared"
|
|
33
33
|
MAPE = "mape"
|
|
34
34
|
WMAPE = "wmape"
|
|
35
|
+
ALL_SUFFIX = "all"
|
|
36
|
+
TRAIN_SUFFIX = "train"
|
|
37
|
+
TEST_SUFFIX = "test"
|
|
38
|
+
EVALUATION_SET_SUFFIXES = (ALL_SUFFIX, TRAIN_SUFFIX, TEST_SUFFIX)
|
|
35
39
|
MEAN = "mean"
|
|
36
40
|
VARIANCE = "variance"
|
|
37
41
|
MEDIAN = "median"
|
|
@@ -319,18 +319,12 @@ class GoodnessOfFitCases(ModelCheckCase, enum.Enum):
|
|
|
319
319
|
|
|
320
320
|
PASS = (
|
|
321
321
|
Status.PASS,
|
|
322
|
-
|
|
323
|
-
"R-squared = {r_squared:.4f}, MAPE = {mape:.4f}, and wMAPE ="
|
|
324
|
-
" {wmape:.4f}."
|
|
325
|
-
),
|
|
322
|
+
"R-squared = {r_squared:.4f}, MAPE = {mape:.4f}, and wMAPE = {wmape:.4f}",
|
|
326
323
|
_GOODNESS_OF_FIT_PASS_RECOMMENDATION,
|
|
327
324
|
)
|
|
328
325
|
REVIEW = (
|
|
329
326
|
Status.REVIEW,
|
|
330
|
-
|
|
331
|
-
"R-squared = {r_squared:.4f}, MAPE = {mape:.4f}, and wMAPE ="
|
|
332
|
-
" {wmape:.4f}."
|
|
333
|
-
),
|
|
327
|
+
"R-squared = {r_squared:.4f}, MAPE = {mape:.4f}, and wMAPE = {wmape:.4f}",
|
|
334
328
|
_GOODNESS_OF_FIT_REVIEW_RECOMMENDATION,
|
|
335
329
|
)
|
|
336
330
|
|
|
@@ -348,9 +342,28 @@ class GoodnessOfFitCheckResult(CheckResult):
|
|
|
348
342
|
"""The immutable result of the Goodness of Fit Check."""
|
|
349
343
|
|
|
350
344
|
case: GoodnessOfFitCases
|
|
345
|
+
is_holdout: bool = False
|
|
351
346
|
|
|
352
347
|
def __post_init__(self):
|
|
353
|
-
if
|
|
348
|
+
if self.is_holdout:
|
|
349
|
+
required_keys = []
|
|
350
|
+
for suffix in [
|
|
351
|
+
constants.ALL_SUFFIX,
|
|
352
|
+
constants.TRAIN_SUFFIX,
|
|
353
|
+
constants.TEST_SUFFIX,
|
|
354
|
+
]:
|
|
355
|
+
required_keys.extend([
|
|
356
|
+
f"{constants.R_SQUARED}_{suffix}",
|
|
357
|
+
f"{constants.MAPE}_{suffix}",
|
|
358
|
+
f"{constants.WMAPE}_{suffix}",
|
|
359
|
+
])
|
|
360
|
+
if any(key not in self.details for key in required_keys):
|
|
361
|
+
raise ValueError(
|
|
362
|
+
"The message template is missing required formatting arguments for"
|
|
363
|
+
f" holdout case. Required keys: {required_keys}. Details:"
|
|
364
|
+
f" {self.details}."
|
|
365
|
+
)
|
|
366
|
+
elif any(
|
|
354
367
|
key not in self.details
|
|
355
368
|
for key in (
|
|
356
369
|
constants.R_SQUARED,
|
|
@@ -364,6 +377,24 @@ class GoodnessOfFitCheckResult(CheckResult):
|
|
|
364
377
|
f" {self.details}."
|
|
365
378
|
)
|
|
366
379
|
|
|
380
|
+
@property
|
|
381
|
+
def recommendation(self) -> str:
|
|
382
|
+
"""Returns the check result message."""
|
|
383
|
+
if self.is_holdout:
|
|
384
|
+
report_str = (
|
|
385
|
+
"R-squared = {r_squared_all:.4f} (All),"
|
|
386
|
+
" {r_squared_train:.4f} (Train), {r_squared_test:.4f} (Test); MAPE"
|
|
387
|
+
" = {mape_all:.4f} (All), {mape_train:.4f} (Train),"
|
|
388
|
+
" {mape_test:.4f} (Test); wMAPE = {wmape_all:.4f} (All),"
|
|
389
|
+
" {wmape_train:.4f} (Train), {wmape_test:.4f} (Test)".format(
|
|
390
|
+
**self.details
|
|
391
|
+
)
|
|
392
|
+
)
|
|
393
|
+
else:
|
|
394
|
+
report_str = self.case.message_template.format(**self.details)
|
|
395
|
+
|
|
396
|
+
return f"{report_str}. {self.case.recommendation}"
|
|
397
|
+
|
|
367
398
|
|
|
368
399
|
# ==============================================================================
|
|
369
400
|
# Check: ROI Consistency
|
|
@@ -21,11 +21,11 @@ import os
|
|
|
21
21
|
import jinja2
|
|
22
22
|
from meridian import constants as c
|
|
23
23
|
from meridian.analysis import analyzer
|
|
24
|
-
from meridian.analysis import formatter
|
|
25
24
|
from meridian.analysis import summary_text
|
|
26
25
|
from meridian.analysis import visualizer
|
|
27
26
|
from meridian.data import time_coordinates as tc
|
|
28
27
|
from meridian.model import model
|
|
28
|
+
from meridian.templates import formatter
|
|
29
29
|
import pandas as pd
|
|
30
30
|
import xarray as xr
|
|
31
31
|
|
|
@@ -318,7 +318,7 @@ class Summarizer:
|
|
|
318
318
|
chart_json=media_summary.plot_contribution_waterfall_chart().to_json(),
|
|
319
319
|
)
|
|
320
320
|
lead_channels = self._get_sorted_posterior_mean_metrics_df(
|
|
321
|
-
media_summary, [c.INCREMENTAL_OUTCOME]
|
|
321
|
+
media_summary, [c.INCREMENTAL_OUTCOME], include_non_paid_channels=True
|
|
322
322
|
)[c.CHANNEL][:2]
|
|
323
323
|
formatted_channels = [channel.title() for channel in lead_channels]
|
|
324
324
|
|
|
@@ -358,9 +358,14 @@ class Summarizer:
|
|
|
358
358
|
media_summary: visualizer.MediaSummary,
|
|
359
359
|
metrics: Sequence[str],
|
|
360
360
|
ascending: bool = False,
|
|
361
|
+
include_non_paid_channels: bool = False,
|
|
361
362
|
) -> pd.DataFrame:
|
|
363
|
+
if include_non_paid_channels:
|
|
364
|
+
summary_metrics = media_summary.get_all_summary_metrics()
|
|
365
|
+
else:
|
|
366
|
+
summary_metrics = media_summary.get_paid_summary_metrics()
|
|
362
367
|
return (
|
|
363
|
-
|
|
368
|
+
summary_metrics[metrics]
|
|
364
369
|
.sel(distribution=c.POSTERIOR, metric=c.MEAN)
|
|
365
370
|
.drop_sel(channel=c.ALL_CHANNELS)
|
|
366
371
|
.to_dataframe()
|