google-meridian 1.1.0__tar.gz → 1.1.2__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.
Files changed (52) hide show
  1. {google_meridian-1.1.0/google_meridian.egg-info → google_meridian-1.1.2}/PKG-INFO +6 -2
  2. {google_meridian-1.1.0 → google_meridian-1.1.2}/README.md +1 -1
  3. {google_meridian-1.1.0 → google_meridian-1.1.2/google_meridian.egg-info}/PKG-INFO +6 -2
  4. {google_meridian-1.1.0 → google_meridian-1.1.2}/google_meridian.egg-info/SOURCES.txt +5 -0
  5. {google_meridian-1.1.0 → google_meridian-1.1.2}/google_meridian.egg-info/requires.txt +5 -0
  6. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/__init__.py +2 -2
  7. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/analysis/__init__.py +1 -1
  8. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/analysis/analyzer.py +29 -22
  9. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/analysis/formatter.py +1 -1
  10. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/analysis/optimizer.py +70 -44
  11. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/analysis/summarizer.py +1 -1
  12. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/analysis/summary_text.py +1 -1
  13. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/analysis/test_utils.py +1 -1
  14. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/analysis/visualizer.py +17 -8
  15. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/constants.py +3 -3
  16. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/data/__init__.py +4 -1
  17. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/data/arg_builder.py +1 -1
  18. google_meridian-1.1.2/meridian/data/data_frame_input_data_builder.py +614 -0
  19. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/data/input_data.py +12 -8
  20. google_meridian-1.1.2/meridian/data/input_data_builder.py +817 -0
  21. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/data/load.py +121 -428
  22. google_meridian-1.1.2/meridian/data/nd_array_input_data_builder.py +509 -0
  23. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/data/test_utils.py +60 -43
  24. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/data/time_coordinates.py +1 -1
  25. google_meridian-1.1.2/meridian/mlflow/__init__.py +17 -0
  26. google_meridian-1.1.2/meridian/mlflow/autolog.py +54 -0
  27. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/model/__init__.py +1 -1
  28. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/model/adstock_hill.py +1 -1
  29. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/model/knots.py +1 -1
  30. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/model/media.py +1 -1
  31. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/model/model.py +65 -37
  32. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/model/model_test_data.py +75 -1
  33. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/model/posterior_sampler.py +19 -15
  34. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/model/prior_distribution.py +1 -1
  35. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/model/prior_sampler.py +32 -26
  36. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/model/spec.py +18 -8
  37. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/model/transformers.py +1 -1
  38. {google_meridian-1.1.0 → google_meridian-1.1.2}/pyproject.toml +5 -0
  39. {google_meridian-1.1.0 → google_meridian-1.1.2}/setup.py +1 -1
  40. {google_meridian-1.1.0 → google_meridian-1.1.2}/LICENSE +0 -0
  41. {google_meridian-1.1.0 → google_meridian-1.1.2}/MANIFEST.in +0 -0
  42. {google_meridian-1.1.0 → google_meridian-1.1.2}/google_meridian.egg-info/dependency_links.txt +0 -0
  43. {google_meridian-1.1.0 → google_meridian-1.1.2}/google_meridian.egg-info/top_level.txt +0 -0
  44. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/analysis/templates/card.html.jinja +0 -0
  45. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/analysis/templates/chart.html.jinja +0 -0
  46. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/analysis/templates/chips.html.jinja +0 -0
  47. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/analysis/templates/insights.html.jinja +0 -0
  48. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/analysis/templates/stats.html.jinja +0 -0
  49. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/analysis/templates/style.scss +0 -0
  50. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/analysis/templates/summary.html.jinja +0 -0
  51. {google_meridian-1.1.0 → google_meridian-1.1.2}/meridian/analysis/templates/table.html.jinja +0 -0
  52. {google_meridian-1.1.0 → google_meridian-1.1.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: google-meridian
3
- Version: 1.1.0
3
+ Version: 1.1.2
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
  License:
@@ -222,6 +222,7 @@ Requires-Dist: arviz
222
222
  Requires-Dist: altair>=5
223
223
  Requires-Dist: immutabledict
224
224
  Requires-Dist: joblib
225
+ Requires-Dist: natsort<8,>=7.1.1
225
226
  Requires-Dist: numpy<3,>=2.0.2
226
227
  Requires-Dist: pandas<3,>=2.2.2
227
228
  Requires-Dist: scipy<2,>=1.13.1
@@ -236,8 +237,11 @@ Requires-Dist: pylint>=2.6.0; extra == "dev"
236
237
  Requires-Dist: pyink; extra == "dev"
237
238
  Provides-Extra: colab
238
239
  Requires-Dist: psutil; extra == "colab"
240
+ Requires-Dist: python-calamine; extra == "colab"
239
241
  Provides-Extra: and-cuda
240
242
  Requires-Dist: tensorflow[and-cuda]<2.19,>=2.18; extra == "and-cuda"
243
+ Provides-Extra: mlflow
244
+ Requires-Dist: mlflow; extra == "mlflow"
241
245
  Dynamic: license-file
242
246
 
243
247
  # About Meridian
@@ -393,7 +397,7 @@ To cite this repository:
393
397
  author = {Google Meridian Marketing Mix Modeling Team},
394
398
  title = {Meridian: Marketing Mix Modeling},
395
399
  url = {https://github.com/google/meridian},
396
- version = {1.1.0},
400
+ version = {1.1.2},
397
401
  year = {2025},
398
402
  }
399
403
  ```
@@ -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.1.0},
154
+ version = {1.1.2},
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.1.0
3
+ Version: 1.1.2
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
  License:
@@ -222,6 +222,7 @@ Requires-Dist: arviz
222
222
  Requires-Dist: altair>=5
223
223
  Requires-Dist: immutabledict
224
224
  Requires-Dist: joblib
225
+ Requires-Dist: natsort<8,>=7.1.1
225
226
  Requires-Dist: numpy<3,>=2.0.2
226
227
  Requires-Dist: pandas<3,>=2.2.2
227
228
  Requires-Dist: scipy<2,>=1.13.1
@@ -236,8 +237,11 @@ Requires-Dist: pylint>=2.6.0; extra == "dev"
236
237
  Requires-Dist: pyink; extra == "dev"
237
238
  Provides-Extra: colab
238
239
  Requires-Dist: psutil; extra == "colab"
240
+ Requires-Dist: python-calamine; extra == "colab"
239
241
  Provides-Extra: and-cuda
240
242
  Requires-Dist: tensorflow[and-cuda]<2.19,>=2.18; extra == "and-cuda"
243
+ Provides-Extra: mlflow
244
+ Requires-Dist: mlflow; extra == "mlflow"
241
245
  Dynamic: license-file
242
246
 
243
247
  # About Meridian
@@ -393,7 +397,7 @@ To cite this repository:
393
397
  author = {Google Meridian Marketing Mix Modeling Team},
394
398
  title = {Meridian: Marketing Mix Modeling},
395
399
  url = {https://github.com/google/meridian},
396
- version = {1.1.0},
400
+ version = {1.1.2},
397
401
  year = {2025},
398
402
  }
399
403
  ```
@@ -28,10 +28,15 @@ meridian/analysis/templates/summary.html.jinja
28
28
  meridian/analysis/templates/table.html.jinja
29
29
  meridian/data/__init__.py
30
30
  meridian/data/arg_builder.py
31
+ meridian/data/data_frame_input_data_builder.py
31
32
  meridian/data/input_data.py
33
+ meridian/data/input_data_builder.py
32
34
  meridian/data/load.py
35
+ meridian/data/nd_array_input_data_builder.py
33
36
  meridian/data/test_utils.py
34
37
  meridian/data/time_coordinates.py
38
+ meridian/mlflow/__init__.py
39
+ meridian/mlflow/autolog.py
35
40
  meridian/model/__init__.py
36
41
  meridian/model/adstock_hill.py
37
42
  meridian/model/knots.py
@@ -2,6 +2,7 @@ arviz
2
2
  altair>=5
3
3
  immutabledict
4
4
  joblib
5
+ natsort<8,>=7.1.1
5
6
  numpy<3,>=2.0.2
6
7
  pandas<3,>=2.2.2
7
8
  scipy<2,>=1.13.1
@@ -15,9 +16,13 @@ tensorflow[and-cuda]<2.19,>=2.18
15
16
 
16
17
  [colab]
17
18
  psutil
19
+ python-calamine
18
20
 
19
21
  [dev]
20
22
  pytest>=8.0.0
21
23
  pytest-xdist
22
24
  pylint>=2.6.0
23
25
  pyink
26
+
27
+ [mlflow]
28
+ mlflow
@@ -1,4 +1,4 @@
1
- # Copyright 2024 The Meridian Authors.
1
+ # Copyright 2025 The Meridian Authors.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -14,7 +14,7 @@
14
14
 
15
15
  """Meridian API."""
16
16
 
17
- __version__ = "1.1.0"
17
+ __version__ = "1.1.2"
18
18
 
19
19
 
20
20
  from meridian import analysis
@@ -1,4 +1,4 @@
1
- # Copyright 2024 The Meridian Authors.
1
+ # Copyright 2025 The Meridian Authors.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright 2024 The Meridian Authors.
1
+ # Copyright 2025 The Meridian Authors.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -788,7 +788,7 @@ class Analyzer:
788
788
  tensors are expected to be scaled by their corresponding transformers.
789
789
  dist_tensors: A `DistributionTensors` container with the distribution
790
790
  tensors for media, RF, organic media, organic RF, non-media treatments,
791
- and controls.
791
+ and controls (if available).
792
792
 
793
793
  Returns:
794
794
  Tensor representing computed kpi means.
@@ -803,17 +803,15 @@ class Analyzer:
803
803
  )
804
804
  )
805
805
 
806
- result = (
807
- tau_gt
808
- + tf.einsum(
809
- "...gtm,...gm->...gt", combined_media_transformed, combined_beta
810
- )
811
- + tf.einsum(
812
- "...gtc,...gc->...gt",
813
- data_tensors.controls,
814
- dist_tensors.gamma_gc,
815
- )
806
+ result = tau_gt + tf.einsum(
807
+ "...gtm,...gm->...gt", combined_media_transformed, combined_beta
816
808
  )
809
+ if self._meridian.controls is not None:
810
+ result += tf.einsum(
811
+ "...gtc,...gc->...gt",
812
+ data_tensors.controls,
813
+ dist_tensors.gamma_gc,
814
+ )
817
815
  if data_tensors.non_media_treatments is not None:
818
816
  result += tf.einsum(
819
817
  "...gtm,...gm->...gt",
@@ -1464,11 +1462,14 @@ class Analyzer:
1464
1462
  (n_chains, 0, self._meridian.n_geos, self._meridian.n_times)
1465
1463
  )
1466
1464
  batch_starting_indices = np.arange(n_draws, step=batch_size)
1467
- param_list = [
1468
- constants.MU_T,
1469
- constants.TAU_G,
1470
- constants.GAMMA_GC,
1471
- ] + self._get_causal_param_names(include_non_paid_channels=True)
1465
+ param_list = (
1466
+ [
1467
+ constants.MU_T,
1468
+ constants.TAU_G,
1469
+ ]
1470
+ + ([constants.GAMMA_GC] if self._meridian.n_controls else [])
1471
+ + self._get_causal_param_names(include_non_paid_channels=True)
1472
+ )
1472
1473
  outcome_means_temps = []
1473
1474
  for start_index in batch_starting_indices:
1474
1475
  stop_index = np.min([n_draws, start_index + batch_size])
@@ -3960,11 +3961,17 @@ class Analyzer:
3960
3961
  ) -> xr.Dataset:
3961
3962
  """Method to generate a response curves xarray.Dataset.
3962
3963
 
3963
- Response curves are calculated at the national-level, assuming the
3964
- historical flighting pattern across geos and time periods for each media
3965
- channel. A list of multipliers is applied to each media channel's total
3966
- historical spend to obtain the `x-values` at which the channel's response
3967
- curve is calculated.
3964
+ Response curves are calculated in aggregate across geos and time periods,
3965
+ assuming the historical flighting pattern across geos and time periods for
3966
+ each media channel.
3967
+
3968
+ A list of multipliers is applied to each media channel's total historical
3969
+ spend within `selected_geos` and `selected_times` to obtain the x-axis
3970
+ values. The y-axis values are the incremental ouctcome generated by each
3971
+ channel within `selected_geos` and `selected_times` under the counterfactual
3972
+ where media units in each geo and time period are scaled by the
3973
+ corresponding multiplier. (Media units for time periods prior to
3974
+ `selected_times` are also scaled by the multiplier.)
3968
3975
 
3969
3976
  Args:
3970
3977
  spend_multipliers: List of multipliers. Each channel's total spend is
@@ -1,4 +1,4 @@
1
- # Copyright 2024 The Meridian Authors.
1
+ # Copyright 2025 The Meridian Authors.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright 2024 The Meridian Authors.
1
+ # Copyright 2025 The Meridian Authors.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -223,7 +223,7 @@ class OptimizationGrid:
223
223
  if spend_constraint_upper is None:
224
224
  spend_constraint_upper = spend_constraint_default
225
225
  (optimization_lower_bound, optimization_upper_bound) = (
226
- _get_optimization_bounds(
226
+ get_optimization_bounds(
227
227
  n_channels=len(self.channels),
228
228
  spend=spend,
229
229
  round_factor=self.round_factor,
@@ -1307,36 +1307,57 @@ class BudgetOptimizer:
1307
1307
  ) -> OptimizationResults:
1308
1308
  """Finds the optimal budget allocation that maximizes outcome.
1309
1309
 
1310
- Optimization depends on the following:
1311
- 1. Flighting pattern (the relative allocation of a channels' media units
1312
- across geos and time periods, which is held fixed for each channel)
1313
- 2. Cost per media unit (This is assumed to be constant for each channel, and
1314
- can optionally vary by geo and/or time period)
1315
- 3. `pct_of_spend` (center of the spend box constraint for each channel)
1316
- 4. `budget` (total budget used for fixed budget scenarios)
1317
-
1318
- By default, these values are assigned based on the historical data. The
1319
- `pct_of_spend` and `budget` are optimization arguments that can be
1320
- overridden directly. Passing `new_data.media` (or `new_data.reach` or
1321
- `new_data.frequency`) will override both the flighting pattern and cost per
1322
- media unit. Passing `new_data.spend` (or `new_data.rf_spend) will only
1323
- override the cost per media unit.
1324
-
1325
- If `new_data` is passed with a different number of time periods than the
1326
- historical data, then all of the optimization parameters will be inferred
1327
- from it. Default values for `pct_of_spend` and `budget` (if
1328
- `fixed_budget=True`) will be inferred from the `new_data`, but can be
1329
- overridden using the `pct_of_spend` and `budget` arguments.
1330
-
1331
- If `start_date` or `end_date` is specified, then the default values are
1332
- inferred based on the subset of time periods specified. Both start and end
1333
- time selectors should align with the Meridian time dimension coordinates in
1334
- the underlying model if optimizing the original data. If `new_data` is
1335
- provided with a different number of time periods than in `InputData`, then
1336
- the start and end time coordinates must match the time dimensions in
1337
- `new_data.time`. By default, all times periods are used. Either start or
1338
- end time component can be `None` to represent the first or the last time
1339
- coordinate, respectively.
1310
+ Define B to be the historical spend of a channel within `selected_geos` and
1311
+ between `start_date` and `end_date`. When the optimization assigns a new
1312
+ budget N to this channel, the historical media units for each geo and time
1313
+ period are assumed to scale by the ratio N / B. Media units prior to
1314
+ `selected_times` are also scaled by N / B. The incremental outcome of each
1315
+ channel is aggregated over `selected_geos` and between `start_date` and
1316
+ `end_date`.
1317
+
1318
+ The incremental outcome includes the (lagged) amount generated between
1319
+ `start_date` and `end_date` by media executed prior to `start_date`, but it
1320
+ excludes the (lagged) amount generated after `end_date` by media executed
1321
+ between `start_date` and `end_date`. This definition does not require any
1322
+ assumptions about media execution levels, media costs, or revenue per kpi
1323
+ for time periods after `end_date`.
1324
+
1325
+ These assumptions are equivalent to assuming that for each channel, neither
1326
+ the flighting pattern nor the cost per media unit depend on the overall
1327
+ budget assigned to that channel.
1328
+
1329
+ The following optimization parameters are assigned default values based on
1330
+ the model input data:
1331
+ 1. Flighting pattern. This is the relative allocation of a channel's media
1332
+ units across geos and time periods. By default, the historical flighting
1333
+ pattern is used. The default can be overridden by passing
1334
+ `new_data.media`. The flighting pattern is held constant during
1335
+ optimization and does not depend on the overall budget assigned to the
1336
+ channel.
1337
+ 2. Cost per media unit. By default, the historical spend divided by
1338
+ historical media units is used. This can optionally vary by geo or time
1339
+ period or both depending on whether the spend data has geo and time
1340
+ dimensions. The default can be overridden by passing `new_data.spend`.
1341
+ The cost per media unit is held constant during optimization and does not
1342
+ depend on the overall budget assigned to the channel.
1343
+ 3. Center of the spend box constraint for each channel. By default, the
1344
+ historical percentage of spend within `selected_geos` and between
1345
+ `start_date` and `end_date` is used. This can be overridden by passing
1346
+ `pct_of_spend`.
1347
+ 4. Total budget to be allocated (for fixed budget scenarios only). By
1348
+ default, the historical spend within `selected_geos` and between
1349
+ `start_date` and `end_date` is used. This can be overridden by passing
1350
+ `budget`.
1351
+
1352
+ Passing `new_data.media` (or `new_data.reach` or `new_data.frequency`) will
1353
+ override both the flighting pattern and cost per media unit. Passing
1354
+ `new_data.spend` (or `new_data.rf_spend) will only override the cost per
1355
+ media unit.
1356
+
1357
+ If `start_date` or `end_date` is specified, these values must be selected
1358
+ from `new_data.time` (if provided) or from `Meridian.n_times` (if
1359
+ `new_data.time` is not provided). The `start_date` and `end_date` default to
1360
+ the first and last time periods, respectively.
1340
1361
 
1341
1362
  Args:
1342
1363
  new_data: An optional `DataTensors` container with optional tensors:
@@ -1355,9 +1376,13 @@ class BudgetOptimizer:
1355
1376
  dimension coordinates for the duration to run the optimization on.
1356
1377
  Please Use `start_date` and `end_date` instead.
1357
1378
  start_date: Optional start date selector, *inclusive*, in _yyyy-mm-dd_
1358
- format. Default is `None`, i.e. the first time period.
1379
+ format. Default is the first time period of `Meridian.InputData.time` if
1380
+ `new_data` is not provided; otherwise it is the first time period of
1381
+ `new_data.time`.
1359
1382
  end_date: Optional end date selector, *inclusive* in _yyyy-mm-dd_ format.
1360
- Default is `None`, i.e. the last time period.
1383
+ Default is the last time period of `Meridian.InputData.time` if
1384
+ `new_data` is not provided; otherwise it is the last time period of
1385
+ `new_data.time`.
1361
1386
  fixed_budget: Boolean indicating whether it's a fixed budget optimization
1362
1387
  or flexible budget optimization. Defaults to `True`. If `False`, must
1363
1388
  specify either `target_roi` or `target_mroi`.
@@ -1664,7 +1689,7 @@ class BudgetOptimizer:
1664
1689
  )
1665
1690
  spend = budget * valid_pct_of_spend
1666
1691
  (optimization_lower_bound, optimization_upper_bound) = (
1667
- _get_optimization_bounds(
1692
+ get_optimization_bounds(
1668
1693
  n_channels=n_channels,
1669
1694
  spend=spend,
1670
1695
  round_factor=optimization_grid.round_factor,
@@ -1829,7 +1854,7 @@ class BudgetOptimizer:
1829
1854
  spend = budget * valid_pct_of_spend
1830
1855
  round_factor = _get_round_factor(budget, gtol)
1831
1856
  (optimization_lower_bound, optimization_upper_bound) = (
1832
- _get_optimization_bounds(
1857
+ get_optimization_bounds(
1833
1858
  n_channels=n_paid_channels,
1834
1859
  spend=spend,
1835
1860
  round_factor=round_factor,
@@ -2059,17 +2084,17 @@ class BudgetOptimizer:
2059
2084
  c.PAID_DATA + (c.TIME,),
2060
2085
  self._meridian,
2061
2086
  )
2062
- spend = tf.convert_to_tensor(spend, dtype=tf.float32)
2087
+ spend_tensor = tf.convert_to_tensor(spend, dtype=tf.float32)
2063
2088
  hist_spend = tf.convert_to_tensor(hist_spend, dtype=tf.float32)
2064
2089
  (new_media, new_media_spend, new_reach, new_frequency, new_rf_spend) = (
2065
2090
  self._get_incremental_outcome_tensors(
2066
2091
  hist_spend,
2067
- spend,
2092
+ spend_tensor,
2068
2093
  new_data=filled_data.filter_fields(c.PAID_CHANNELS),
2069
2094
  optimal_frequency=optimal_frequency,
2070
2095
  )
2071
2096
  )
2072
- budget = np.sum(spend)
2097
+ budget = np.sum(spend_tensor)
2073
2098
 
2074
2099
  # incremental_outcome here is a tensor with the shape
2075
2100
  # (n_chains, n_draws, n_channels)
@@ -2123,7 +2148,7 @@ class BudgetOptimizer:
2123
2148
  )
2124
2149
 
2125
2150
  roi = analyzer.get_central_tendency_and_ci(
2126
- data=tf.math.divide_no_nan(incremental_outcome, spend),
2151
+ data=tf.math.divide_no_nan(incremental_outcome, spend_tensor),
2127
2152
  confidence_level=confidence_level,
2128
2153
  include_median=True,
2129
2154
  )
@@ -2148,7 +2173,7 @@ class BudgetOptimizer:
2148
2173
  )
2149
2174
 
2150
2175
  cpik = analyzer.get_central_tendency_and_ci(
2151
- data=tf.math.divide_no_nan(spend, incremental_outcome),
2176
+ data=tf.math.divide_no_nan(spend_tensor, incremental_outcome),
2152
2177
  confidence_level=confidence_level,
2153
2178
  include_median=True,
2154
2179
  )
@@ -2159,9 +2184,10 @@ class BudgetOptimizer:
2159
2184
  )
2160
2185
 
2161
2186
  total_spend = np.sum(spend) if np.sum(spend) > 0 else 1
2187
+ pct_of_spend = spend / total_spend
2162
2188
  data_vars = {
2163
- c.SPEND: ([c.CHANNEL], spend),
2164
- c.PCT_OF_SPEND: ([c.CHANNEL], spend / total_spend),
2189
+ c.SPEND: ([c.CHANNEL], spend.data),
2190
+ c.PCT_OF_SPEND: ([c.CHANNEL], pct_of_spend.data),
2165
2191
  c.INCREMENTAL_OUTCOME: (
2166
2192
  [c.CHANNEL, c.METRIC],
2167
2193
  incremental_outcome_with_mean_median_and_ci,
@@ -2510,7 +2536,7 @@ def _get_spend_bounds(
2510
2536
  return spend_bounds
2511
2537
 
2512
2538
 
2513
- def _get_optimization_bounds(
2539
+ def get_optimization_bounds(
2514
2540
  n_channels: int,
2515
2541
  spend: np.ndarray,
2516
2542
  round_factor: int,
@@ -1,4 +1,4 @@
1
- # Copyright 2024 The Meridian Authors.
1
+ # Copyright 2025 The Meridian Authors.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright 2024 The Meridian Authors.
1
+ # Copyright 2025 The Meridian Authors.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright 2024 The Meridian Authors.
1
+ # Copyright 2025 The Meridian Authors.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -1,4 +1,4 @@
1
- # Copyright 2024 The Meridian Authors.
1
+ # Copyright 2025 The Meridian Authors.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -876,9 +876,14 @@ class MediaEffects:
876
876
  Args:
877
877
  confidence_level: Confidence level for modeled response credible
878
878
  intervals, represented as a value between zero and one. Default is 0.9.
879
- selected_times: Optional list of a subset of time dimensions to include.
880
- By default, all times are included. Times should match the time
881
- dimensions from `meridian.InputData`.
879
+ selected_times: Optional list containing a subset of time dimensions to
880
+ include. The x-axis corresponds to spend within these time periods. The
881
+ y-axis corresponds to the incremental outcome generated within these
882
+ time periods under the counterfactual where media units in each geo and
883
+ time period are scaled by the ratio of x-axis spend to historical spend.
884
+ (Media units for time periods prior to to `selected_times` are also
885
+ scaled by this ratio). By default, all times are included. Times should
886
+ match the time dimensions from `meridian.InputData`.
882
887
  by_reach: For the channel w/ reach and frequency, return the response
883
888
  curves by reach given fixed frequency if true; return the response
884
889
  curves by frequency given fixed reach if false.
@@ -972,8 +977,13 @@ class MediaEffects:
972
977
  Args:
973
978
  confidence_level: Confidence level to update to for the response curve
974
979
  credible intervals, represented as a value between zero and one.
975
- selected_times: Optional list containing a subset of times to include. By
976
- default, all time periods are included.
980
+ selected_times: Optional list containing a subset of time dimensions to
981
+ include. The x-axis corresponds to spend within these time periods. The
982
+ y-axis corresponds to the incremental outcome generated within these
983
+ time periods under the counterfactual where media units in each geo and
984
+ time period are multiplied by the corresponding multiplier (including
985
+ time periods prior to to `selected_times`). By default, all time periods
986
+ are included.
977
987
  by_reach: For the channel w/ reach and frequency, return the response
978
988
  curves by reach given fixed frequency if true; return the response
979
989
  curves by frequency given fixed reach if false.
@@ -1493,8 +1503,7 @@ class MediaSummary:
1493
1503
  Returns:
1494
1504
  An `xarray.Dataset` containing the following:
1495
1505
  - **Coordinates:** `channel`, `metric` (`mean`, `median`, `ci_lo`,
1496
- `ci_hi`),
1497
- `distribution` (`prior`, `posterior`)
1506
+ `ci_hi`), `distribution` (`prior`, `posterior`)
1498
1507
  - **Data variables:** `incremental_outcome`, `pct_of_contribution`,
1499
1508
  `effectiveness`.
1500
1509
  """
@@ -1,4 +1,4 @@
1
- # Copyright 2024 The Meridian Authors.
1
+ # Copyright 2025 The Meridian Authors.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -72,10 +72,10 @@ REVENUE = 'revenue'
72
72
  NON_REVENUE = 'non_revenue'
73
73
  REQUIRED_INPUT_DATA_ARRAY_NAMES = (
74
74
  KPI,
75
- CONTROLS,
76
75
  POPULATION,
77
76
  )
78
77
  OPTIONAL_INPUT_DATA_ARRAY_NAMES = (
78
+ CONTROLS,
79
79
  REVENUE_PER_KPI,
80
80
  ORGANIC_MEDIA,
81
81
  ORGANIC_REACH,
@@ -148,7 +148,6 @@ REQUIRED_INPUT_DATA_COORD_NAMES = (
148
148
  GEO,
149
149
  TIME,
150
150
  MEDIA_TIME,
151
- CONTROL_VARIABLE,
152
151
  )
153
152
  NON_PAID_MEDIA_INPUT_DATA_COORD_NAMES = (
154
153
  ORGANIC_MEDIA_CHANNEL,
@@ -159,6 +158,7 @@ MEDIA_INPUT_DATA_COORD_NAMES = (MEDIA_CHANNEL,)
159
158
  RF_INPUT_DATA_COORD_NAMES = (RF_CHANNEL,)
160
159
  POSSIBLE_INPUT_DATA_COORD_NAMES = (
161
160
  REQUIRED_INPUT_DATA_COORD_NAMES
161
+ + (CONTROL_VARIABLE,)
162
162
  + NON_PAID_MEDIA_INPUT_DATA_COORD_NAMES
163
163
  + MEDIA_INPUT_DATA_COORD_NAMES
164
164
  + RF_INPUT_DATA_COORD_NAMES
@@ -1,4 +1,4 @@
1
- # Copyright 2024 The Meridian Authors.
1
+ # Copyright 2025 The Meridian Authors.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -15,6 +15,9 @@
15
15
  """Data handling API for Meridian."""
16
16
 
17
17
  from meridian.data import arg_builder
18
+ from meridian.data import data_frame_input_data_builder
18
19
  from meridian.data import input_data
20
+ from meridian.data import input_data_builder
19
21
  from meridian.data import load
22
+ from meridian.data import nd_array_input_data_builder
20
23
  from meridian.data import time_coordinates
@@ -1,4 +1,4 @@
1
- # Copyright 2024 The Meridian Authors.
1
+ # Copyright 2025 The Meridian Authors.
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.