google-meridian 1.3.1__py3-none-any.whl → 1.4.0__py3-none-any.whl

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 (74) hide show
  1. {google_meridian-1.3.1.dist-info → google_meridian-1.4.0.dist-info}/METADATA +13 -9
  2. google_meridian-1.4.0.dist-info/RECORD +108 -0
  3. {google_meridian-1.3.1.dist-info → google_meridian-1.4.0.dist-info}/top_level.txt +1 -0
  4. meridian/analysis/__init__.py +1 -2
  5. meridian/analysis/analyzer.py +0 -1
  6. meridian/analysis/optimizer.py +5 -3
  7. meridian/analysis/review/checks.py +81 -30
  8. meridian/analysis/review/constants.py +4 -0
  9. meridian/analysis/review/results.py +40 -9
  10. meridian/analysis/summarizer.py +8 -3
  11. meridian/analysis/test_utils.py +934 -485
  12. meridian/analysis/visualizer.py +11 -7
  13. meridian/backend/__init__.py +53 -5
  14. meridian/backend/test_utils.py +72 -0
  15. meridian/constants.py +2 -0
  16. meridian/data/load.py +2 -0
  17. meridian/data/test_utils.py +82 -10
  18. meridian/model/__init__.py +2 -0
  19. meridian/model/context.py +925 -0
  20. meridian/model/eda/__init__.py +0 -1
  21. meridian/model/eda/constants.py +13 -2
  22. meridian/model/eda/eda_engine.py +299 -37
  23. meridian/model/eda/eda_outcome.py +21 -1
  24. meridian/model/equations.py +418 -0
  25. meridian/model/knots.py +75 -47
  26. meridian/model/model.py +93 -792
  27. meridian/{analysis/templates → templates}/card.html.jinja +1 -1
  28. meridian/{analysis/templates → templates}/chart.html.jinja +1 -1
  29. meridian/{analysis/templates → templates}/chips.html.jinja +1 -1
  30. meridian/{analysis → templates}/formatter.py +12 -1
  31. meridian/templates/formatter_test.py +216 -0
  32. meridian/{analysis/templates → templates}/insights.html.jinja +1 -1
  33. meridian/{analysis/templates → templates}/stats.html.jinja +1 -1
  34. meridian/{analysis/templates → templates}/style.css +1 -1
  35. meridian/{analysis/templates → templates}/style.scss +1 -1
  36. meridian/{analysis/templates → templates}/summary.html.jinja +4 -2
  37. meridian/{analysis/templates → templates}/table.html.jinja +1 -1
  38. meridian/version.py +1 -1
  39. scenarioplanner/__init__.py +42 -0
  40. scenarioplanner/converters/__init__.py +25 -0
  41. scenarioplanner/converters/dataframe/__init__.py +28 -0
  42. scenarioplanner/converters/dataframe/budget_opt_converters.py +383 -0
  43. scenarioplanner/converters/dataframe/common.py +71 -0
  44. scenarioplanner/converters/dataframe/constants.py +137 -0
  45. scenarioplanner/converters/dataframe/converter.py +42 -0
  46. scenarioplanner/converters/dataframe/dataframe_model_converter.py +70 -0
  47. scenarioplanner/converters/dataframe/marketing_analyses_converters.py +543 -0
  48. scenarioplanner/converters/dataframe/rf_opt_converters.py +314 -0
  49. scenarioplanner/converters/mmm.py +743 -0
  50. scenarioplanner/converters/mmm_converter.py +58 -0
  51. scenarioplanner/converters/sheets.py +156 -0
  52. scenarioplanner/converters/test_data.py +714 -0
  53. scenarioplanner/linkingapi/__init__.py +47 -0
  54. scenarioplanner/linkingapi/constants.py +27 -0
  55. scenarioplanner/linkingapi/url_generator.py +131 -0
  56. scenarioplanner/mmm_ui_proto_generator.py +354 -0
  57. schema/__init__.py +15 -0
  58. schema/mmm_proto_generator.py +71 -0
  59. schema/model_consumer.py +133 -0
  60. schema/processors/__init__.py +77 -0
  61. schema/processors/budget_optimization_processor.py +832 -0
  62. schema/processors/common.py +64 -0
  63. schema/processors/marketing_processor.py +1136 -0
  64. schema/processors/model_fit_processor.py +367 -0
  65. schema/processors/model_kernel_processor.py +117 -0
  66. schema/processors/model_processor.py +412 -0
  67. schema/processors/reach_frequency_optimization_processor.py +584 -0
  68. schema/test_data.py +380 -0
  69. schema/utils/__init__.py +1 -0
  70. schema/utils/date_range_bucketing.py +117 -0
  71. google_meridian-1.3.1.dist-info/RECORD +0 -76
  72. meridian/model/eda/meridian_eda.py +0 -220
  73. {google_meridian-1.3.1.dist-info → google_meridian-1.4.0.dist-info}/WHEEL +0 -0
  74. {google_meridian-1.3.1.dist-info → google_meridian-1.4.0.dist-info}/licenses/LICENSE +0 -0
schema/test_data.py ADDED
@@ -0,0 +1,380 @@
1
+ # Copyright 2025 The Meridian Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Test data for MMM proto generator."""
16
+
17
+ from collections.abc import Sequence
18
+ import datetime
19
+
20
+ from mmm.v1 import mmm_pb2 as mmm_pb
21
+ from mmm.v1.common import date_interval_pb2 as date_interval_pb
22
+ from mmm.v1.fit import model_fit_pb2 as fit_pb
23
+ from mmm.v1.marketing.analysis import marketing_analysis_pb2
24
+ from mmm.v1.marketing.optimization import budget_optimization_pb2 as budget_pb
25
+ from mmm.v1.marketing.optimization import reach_frequency_optimization_pb2 as rf_pb
26
+ from schema.processors import budget_optimization_processor
27
+ from schema.processors import marketing_processor
28
+ from schema.processors import model_fit_processor
29
+ from schema.processors import model_processor
30
+ from schema.processors import reach_frequency_optimization_processor as rf_opt_processor
31
+
32
+ from google.type import date_pb2
33
+
34
+ # Weekly dates from 2022-11-21 to 2024-01-01.
35
+ ALL_TIMES_IN_MERIDIAN = (
36
+ '2022-11-21',
37
+ '2022-11-28',
38
+ '2022-12-05',
39
+ '2022-12-12',
40
+ '2022-12-19',
41
+ '2022-12-26',
42
+ '2023-01-02',
43
+ '2023-01-09',
44
+ '2023-01-16',
45
+ '2023-01-23',
46
+ '2023-01-30',
47
+ '2023-02-06',
48
+ '2023-02-13',
49
+ '2023-02-20',
50
+ '2023-02-27',
51
+ '2023-03-06',
52
+ '2023-03-13',
53
+ '2023-03-20',
54
+ '2023-03-27',
55
+ '2023-04-03',
56
+ '2023-04-10',
57
+ '2023-04-17',
58
+ '2023-04-24',
59
+ '2023-05-01',
60
+ '2023-05-08',
61
+ '2023-05-15',
62
+ '2023-05-22',
63
+ '2023-05-29',
64
+ '2023-06-05',
65
+ '2023-06-12',
66
+ '2023-06-19',
67
+ '2023-06-26',
68
+ '2023-07-03',
69
+ '2023-07-10',
70
+ '2023-07-17',
71
+ '2023-07-24',
72
+ '2023-07-31',
73
+ '2023-08-07',
74
+ '2023-08-14',
75
+ '2023-08-21',
76
+ '2023-08-28',
77
+ '2023-09-04',
78
+ '2023-09-11',
79
+ '2023-09-18',
80
+ '2023-09-25',
81
+ '2023-10-02',
82
+ '2023-10-09',
83
+ '2023-10-16',
84
+ '2023-10-23',
85
+ '2023-10-30',
86
+ '2023-11-06',
87
+ '2023-11-13',
88
+ '2023-11-20',
89
+ '2023-11-27',
90
+ '2023-12-04',
91
+ '2023-12-11',
92
+ '2023-12-18',
93
+ '2023-12-25',
94
+ '2024-01-01',
95
+ )
96
+
97
+ ALL_TIME_BUCKET_DATED_SPECS = (
98
+ # All
99
+ model_processor.DatedSpec(
100
+ start_date=datetime.date(2022, 11, 21),
101
+ end_date=datetime.date(2024, 1, 8),
102
+ date_interval_tag='ALL',
103
+ ),
104
+ # Monthly buckets
105
+ model_processor.DatedSpec(
106
+ start_date=datetime.date(2022, 12, 5),
107
+ end_date=datetime.date(2023, 1, 2),
108
+ date_interval_tag='Y2022 Dec',
109
+ ),
110
+ model_processor.DatedSpec(
111
+ start_date=datetime.date(2023, 1, 2),
112
+ end_date=datetime.date(2023, 2, 6),
113
+ date_interval_tag='Y2023 Jan',
114
+ ),
115
+ model_processor.DatedSpec(
116
+ start_date=datetime.date(2023, 2, 6),
117
+ end_date=datetime.date(2023, 3, 6),
118
+ date_interval_tag='Y2023 Feb',
119
+ ),
120
+ model_processor.DatedSpec(
121
+ start_date=datetime.date(2023, 3, 6),
122
+ end_date=datetime.date(2023, 4, 3),
123
+ date_interval_tag='Y2023 Mar',
124
+ ),
125
+ model_processor.DatedSpec(
126
+ start_date=datetime.date(2023, 4, 3),
127
+ end_date=datetime.date(2023, 5, 1),
128
+ date_interval_tag='Y2023 Apr',
129
+ ),
130
+ model_processor.DatedSpec(
131
+ start_date=datetime.date(2023, 5, 1),
132
+ end_date=datetime.date(2023, 6, 5),
133
+ date_interval_tag='Y2023 May',
134
+ ),
135
+ model_processor.DatedSpec(
136
+ start_date=datetime.date(2023, 6, 5),
137
+ end_date=datetime.date(2023, 7, 3),
138
+ date_interval_tag='Y2023 Jun',
139
+ ),
140
+ model_processor.DatedSpec(
141
+ start_date=datetime.date(2023, 7, 3),
142
+ end_date=datetime.date(2023, 8, 7),
143
+ date_interval_tag='Y2023 Jul',
144
+ ),
145
+ model_processor.DatedSpec(
146
+ start_date=datetime.date(2023, 8, 7),
147
+ end_date=datetime.date(2023, 9, 4),
148
+ date_interval_tag='Y2023 Aug',
149
+ ),
150
+ model_processor.DatedSpec(
151
+ start_date=datetime.date(2023, 9, 4),
152
+ end_date=datetime.date(2023, 10, 2),
153
+ date_interval_tag='Y2023 Sep',
154
+ ),
155
+ model_processor.DatedSpec(
156
+ start_date=datetime.date(2023, 10, 2),
157
+ end_date=datetime.date(2023, 11, 6),
158
+ date_interval_tag='Y2023 Oct',
159
+ ),
160
+ model_processor.DatedSpec(
161
+ start_date=datetime.date(2023, 11, 6),
162
+ end_date=datetime.date(2023, 12, 4),
163
+ date_interval_tag='Y2023 Nov',
164
+ ),
165
+ model_processor.DatedSpec(
166
+ start_date=datetime.date(2023, 12, 4),
167
+ end_date=datetime.date(2024, 1, 1),
168
+ date_interval_tag='Y2023 Dec',
169
+ ),
170
+ # Quarterly buckets
171
+ model_processor.DatedSpec(
172
+ start_date=datetime.date(2023, 1, 2),
173
+ end_date=datetime.date(2023, 4, 3),
174
+ date_interval_tag='Y2023 Q1',
175
+ ),
176
+ model_processor.DatedSpec(
177
+ start_date=datetime.date(2023, 4, 3),
178
+ end_date=datetime.date(2023, 7, 3),
179
+ date_interval_tag='Y2023 Q2',
180
+ ),
181
+ model_processor.DatedSpec(
182
+ start_date=datetime.date(2023, 7, 3),
183
+ end_date=datetime.date(2023, 10, 2),
184
+ date_interval_tag='Y2023 Q3',
185
+ ),
186
+ model_processor.DatedSpec(
187
+ start_date=datetime.date(2023, 10, 2),
188
+ end_date=datetime.date(2024, 1, 1),
189
+ date_interval_tag='Y2023 Q4',
190
+ ),
191
+ # Yearly buckets
192
+ model_processor.DatedSpec(
193
+ start_date=datetime.date(2023, 1, 2),
194
+ end_date=datetime.date(2024, 1, 1),
195
+ date_interval_tag='Y2023',
196
+ ),
197
+ )
198
+
199
+
200
+ def _dated_spec_to_date_interval(
201
+ spec: model_processor.DatedSpec,
202
+ ) -> date_interval_pb.DateInterval:
203
+ if spec.start_date is None or spec.end_date is None:
204
+ raise ValueError('Start date or end date is None.')
205
+
206
+ return date_interval_pb.DateInterval(
207
+ start_date=date_pb2.Date(
208
+ year=spec.start_date.year,
209
+ month=spec.start_date.month,
210
+ day=spec.start_date.day,
211
+ ),
212
+ end_date=date_pb2.Date(
213
+ year=spec.end_date.year,
214
+ month=spec.end_date.month,
215
+ day=spec.end_date.day,
216
+ ),
217
+ tag=spec.date_interval_tag,
218
+ )
219
+
220
+
221
+ class FakeModelFitProcessor(
222
+ model_processor.ModelProcessor[
223
+ model_fit_processor.ModelFitSpec, fit_pb.ModelFit
224
+ ]
225
+ ):
226
+ """Fake ModelFitProcessor for testing."""
227
+
228
+ def __init__(self, trained_model: model_processor.TrainedModel):
229
+ self._trained_model = trained_model
230
+
231
+ @classmethod
232
+ def spec_type(cls):
233
+ return model_fit_processor.ModelFitSpec
234
+
235
+ @classmethod
236
+ def output_type(cls):
237
+ return fit_pb.ModelFit
238
+
239
+ def execute(
240
+ self, specs: Sequence[model_fit_processor.ModelFitSpec]
241
+ ) -> fit_pb.ModelFit:
242
+ return fit_pb.ModelFit()
243
+
244
+ def _set_output(self, output: mmm_pb.Mmm, result: fit_pb.ModelFit):
245
+ output.model_fit.CopyFrom(result)
246
+
247
+
248
+ class FakeBudgetOptimizationProcessor(
249
+ model_processor.ModelProcessor[
250
+ budget_optimization_processor.BudgetOptimizationSpec,
251
+ budget_pb.BudgetOptimization,
252
+ ]
253
+ ):
254
+ """Fake BudgetOptimizationProcessor for testing."""
255
+
256
+ def __init__(self, trained_model: model_processor.TrainedModel):
257
+ self._trained_model = trained_model
258
+
259
+ @classmethod
260
+ def spec_type(cls):
261
+ return budget_optimization_processor.BudgetOptimizationSpec
262
+
263
+ @classmethod
264
+ def output_type(cls):
265
+ return budget_pb.BudgetOptimization
266
+
267
+ def execute(
268
+ self,
269
+ specs: Sequence[budget_optimization_processor.BudgetOptimizationSpec],
270
+ ) -> budget_pb.BudgetOptimization:
271
+ results = []
272
+ for spec in specs:
273
+ result = budget_pb.BudgetOptimizationResult(
274
+ name=spec.optimization_name,
275
+ spec=budget_pb.BudgetOptimizationSpec(
276
+ date_interval=_dated_spec_to_date_interval(spec)
277
+ ),
278
+ incremental_outcome_grid=budget_pb.IncrementalOutcomeGrid(
279
+ name=spec.grid_name
280
+ ),
281
+ )
282
+ if spec.group_id:
283
+ result.group_id = spec.group_id
284
+ results.append(result)
285
+
286
+ return budget_pb.BudgetOptimization(results=results)
287
+
288
+ def _set_output(
289
+ self, output: mmm_pb.Mmm, result: budget_pb.BudgetOptimization
290
+ ):
291
+ output.marketing_optimization.budget_optimization.CopyFrom(result)
292
+
293
+
294
+ class FakeReachFrequencyOptimizationProcessor(
295
+ model_processor.ModelProcessor[
296
+ rf_opt_processor.ReachFrequencyOptimizationSpec,
297
+ rf_pb.ReachFrequencyOptimization,
298
+ ]
299
+ ):
300
+ """Fake ReachFrequencyOptimizationProcessor for testing."""
301
+
302
+ def __init__(self, trained_model: model_processor.TrainedModel):
303
+ self._trained_model = trained_model
304
+
305
+ @classmethod
306
+ def spec_type(cls):
307
+ return rf_opt_processor.ReachFrequencyOptimizationSpec
308
+
309
+ @classmethod
310
+ def output_type(cls):
311
+ return rf_pb.ReachFrequencyOptimization
312
+
313
+ def execute(
314
+ self,
315
+ specs: Sequence[rf_opt_processor.ReachFrequencyOptimizationSpec],
316
+ ) -> rf_pb.ReachFrequencyOptimization:
317
+ results = []
318
+ for spec in specs:
319
+ result = rf_pb.ReachFrequencyOptimizationResult(
320
+ name=spec.optimization_name,
321
+ spec=rf_pb.ReachFrequencyOptimizationSpec(
322
+ date_interval=_dated_spec_to_date_interval(spec)
323
+ ),
324
+ frequency_outcome_grid=rf_pb.FrequencyOutcomeGrid(
325
+ name=spec.grid_name
326
+ ),
327
+ )
328
+ if spec.group_id:
329
+ result.group_id = spec.group_id
330
+ results.append(result)
331
+
332
+ return rf_pb.ReachFrequencyOptimization(results=results)
333
+
334
+ def _set_output(
335
+ self,
336
+ output: mmm_pb.Mmm,
337
+ result: rf_pb.ReachFrequencyOptimization,
338
+ ):
339
+ output.marketing_optimization.reach_frequency_optimization.CopyFrom(result)
340
+
341
+
342
+ class FakeMarketingProcessor(
343
+ model_processor.ModelProcessor[
344
+ marketing_processor.MarketingAnalysisSpec,
345
+ marketing_analysis_pb2.MarketingAnalysisList,
346
+ ]
347
+ ):
348
+ """Fake MarketingProcessor for testing."""
349
+
350
+ def __init__(self, trained_model: model_processor.TrainedModel):
351
+ self._trained_model = trained_model
352
+
353
+ @classmethod
354
+ def spec_type(cls):
355
+ return marketing_processor.MarketingAnalysisSpec
356
+
357
+ @classmethod
358
+ def output_type(cls):
359
+ return marketing_analysis_pb2.MarketingAnalysisList
360
+
361
+ def execute(
362
+ self, specs: Sequence[marketing_processor.MarketingAnalysisSpec]
363
+ ) -> marketing_analysis_pb2.MarketingAnalysisList:
364
+ marketing_analyses = []
365
+ for spec in specs:
366
+ marketing_analysis = marketing_analysis_pb2.MarketingAnalysis(
367
+ date_interval=_dated_spec_to_date_interval(spec)
368
+ )
369
+ marketing_analyses.append(marketing_analysis)
370
+
371
+ return marketing_analysis_pb2.MarketingAnalysisList(
372
+ marketing_analyses=marketing_analyses
373
+ )
374
+
375
+ def _set_output(
376
+ self,
377
+ output: mmm_pb.Mmm,
378
+ result: marketing_analysis_pb2.MarketingAnalysisList,
379
+ ):
380
+ output.marketing_analysis_list.CopyFrom(result)
schema/utils/__init__.py CHANGED
@@ -14,4 +14,5 @@
14
14
 
15
15
  """Module containing MMM schema util functions."""
16
16
 
17
+ from schema.utils import date_range_bucketing
17
18
  from schema.utils import time_record
@@ -0,0 +1,117 @@
1
+ # Copyright 2025 The Meridian Authors.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Helper classes for generating date intervals for various time buckets."""
16
+
17
+ import abc
18
+ from collections.abc import Iterator, Sequence
19
+ import datetime
20
+ from typing import TypeAlias
21
+
22
+
23
+ __all__ = [
24
+ "DateRangeBucketer",
25
+ "MonthlyDateRangeGenerator",
26
+ "QuarterlyDateRangeGenerator",
27
+ "YearlyDateRangeGenerator",
28
+ ]
29
+
30
+
31
+ DateInterval: TypeAlias = tuple[datetime.date, datetime.date]
32
+
33
+
34
+ class DateRangeBucketer(abc.ABC):
35
+ """Generates `DateInterval` protos over a range of dates."""
36
+
37
+ def __init__(
38
+ self,
39
+ input_dates: Sequence[datetime.date],
40
+ ):
41
+ """Initializes the DateRangeBucketer with a sequence of dates.
42
+
43
+ Args:
44
+ input_dates: A sequence of `datetime.date` objects representing the range
45
+ of dates to generate intervals for.
46
+ """
47
+ if not all(
48
+ input_dates[i] < input_dates[i + 1] for i in range(len(input_dates) - 1)
49
+ ):
50
+ raise ValueError("`input_dates` must be strictly ascending dates.")
51
+
52
+ self._input_dates = input_dates
53
+
54
+ @abc.abstractmethod
55
+ def generate_date_intervals(self) -> Iterator[DateInterval]:
56
+ """Generates `DateInterval` protos for the class's input dates.
57
+
58
+ Each interval represents a month, quarter, or year, depending on the
59
+ instance of this class. An interval is excluded if the start date is not the
60
+ first available date (in `self._input_dates`) for the time bucket. The last
61
+ interval in `self._input_dates` is excluded in all cases.
62
+
63
+ Returns:
64
+ An iterator over generated `TimeInterval`s.
65
+ """
66
+ raise NotImplementedError()
67
+
68
+
69
+ class MonthlyDateRangeGenerator(DateRangeBucketer):
70
+ """Generates monthly date intervals."""
71
+
72
+ def generate_date_intervals(self) -> Iterator[DateInterval]:
73
+ start_date = self._input_dates[0]
74
+
75
+ for date in self._input_dates:
76
+ if date.month != start_date.month:
77
+ if start_date.day <= 7:
78
+ yield (start_date, date)
79
+
80
+ start_date = date
81
+
82
+
83
+ class QuarterlyDateRangeGenerator(DateRangeBucketer):
84
+ """Generates quarterly date intervals."""
85
+
86
+ def generate_date_intervals(self) -> Iterator[DateInterval]:
87
+ start_date = self._input_dates[0]
88
+ for date in self._input_dates:
89
+ start_date_quarter_number = (start_date.month - 1) // 3 + 1
90
+ current_date_quarter_number = (date.month - 1) // 3 + 1
91
+
92
+ if start_date_quarter_number != current_date_quarter_number:
93
+ # The interval is only included if the start date is the first date of
94
+ # the quarter that's present in `self._input_dates`. We can detect this
95
+ # date by checking whether it's in the first month of the quarter and
96
+ # falls in the first seven days of the month.
97
+ if (
98
+ start_date.day <= 7
99
+ and start_date.month == ((start_date_quarter_number - 1) * 3) + 1
100
+ ):
101
+ yield (start_date, date)
102
+
103
+ start_date = date
104
+
105
+
106
+ class YearlyDateRangeGenerator(DateRangeBucketer):
107
+ """Generates yearly date intervals."""
108
+
109
+ def generate_date_intervals(self) -> Iterator[DateInterval]:
110
+ start_date = self._input_dates[0]
111
+
112
+ for date in self._input_dates:
113
+ if date.year != start_date.year:
114
+ if start_date.day <= 7 and start_date.month == 1:
115
+ yield (start_date, date)
116
+
117
+ start_date = date
@@ -1,76 +0,0 @@
1
- google_meridian-1.3.1.dist-info/licenses/LICENSE,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
2
- meridian/__init__.py,sha256=0fOT5oNZF7-pbiWWGUefV-ysafttieG079m1ijMFQO8,861
3
- meridian/constants.py,sha256=ZmMIoJDFQvKIOVG9oPOQ7Cj16wt4HDS5fCPBrz_KiLE,20308
4
- meridian/version.py,sha256=mmCkrGRWB8mI33apVnverT2ysfJofSyhlXSCVNotj9U,644
5
- meridian/analysis/__init__.py,sha256=NWDhtRkKs-n66C6746rXT7Wk8tLdkrT9NDvuPG_B_5c,874
6
- meridian/analysis/analyzer.py,sha256=EUKoN69EEz4vt4BpyRvrwEoHt7eLZ8UM6emNe14Tbj0,219975
7
- meridian/analysis/formatter.py,sha256=AN2M4jdUV88XjNdi5-dK_mITES1J1Dk3Zs7DYo3OTKg,7290
8
- meridian/analysis/optimizer.py,sha256=RX8HXSUi-tvLSjzF2OIbXQT3pMT75PzA5Y0xK6PPE_I,126277
9
- meridian/analysis/summarizer.py,sha256=7hHBf2Bj0lKqamg7DGvaKIuCf06CSsPPhDM2wKsXUPk,19035
10
- meridian/analysis/summary_text.py,sha256=I_smDkZJYp2j77ea-9AIbgeraDa7-qUYyb-IthP2qO4,12438
11
- meridian/analysis/test_utils.py,sha256=aZq88pxtpMHwhcpfYz8nHhR0Alhi_OvgS9qBR4LBgO0,78346
12
- meridian/analysis/visualizer.py,sha256=1vjX3XQF_BoXEGDUS4o2GheZQ5c0VGdHuc-nXySnpsY,94091
13
- meridian/analysis/review/__init__.py,sha256=cF24EbhiVSs-tvtRf59uVin39tu6aCTTCaeEdv6ISZ8,804
14
- meridian/analysis/review/checks.py,sha256=CBBZ0uNN91b_0H9DGdbDRVdiTRI4D7xptLCq_gK5WAI,25002
15
- meridian/analysis/review/configs.py,sha256=5JJ8v6n22GNBmE78xNX6jwdjkZz2qar4Q9YTcVqzcoI,3653
16
- meridian/analysis/review/constants.py,sha256=bL-se2BFfRxPr3F0Rfpdy7d8s3idMoaka_t6hN1K3Sc,1369
17
- meridian/analysis/review/results.py,sha256=jsOPohmwozCrx8yt9p7_GiVxGmRDVeAbA8W48MUfAPA,16168
18
- meridian/analysis/review/reviewer.py,sha256=BcfmqHjp-30iZBlrzWfXDN1IJU-UIjINxZ7lsrj5Mts,6675
19
- meridian/analysis/templates/card.html.jinja,sha256=pv4MVbQ25CcvtZY-LH7bFW0OSeHobkeEkAleB1sfQ14,1284
20
- meridian/analysis/templates/chart.html.jinja,sha256=87i0xnXHRBoLLxBpKv2i960TLToWq4r1aVQZqaXIeMQ,1086
21
- meridian/analysis/templates/chips.html.jinja,sha256=t-ovn-2pcPCn1ev1VtSaSC3W7QxSy_iAO_L5-p68mdg,1030
22
- meridian/analysis/templates/insights.html.jinja,sha256=6hEWipbOMiMzs9QGZ6dcB_73tNkj0ZtNiC8E89a98zg,606
23
- meridian/analysis/templates/stats.html.jinja,sha256=9hQOG02FX1IHVIvdWS_-LI2bbSaqdyHEtCZkiArwAg0,772
24
- meridian/analysis/templates/style.css,sha256=RODTWc2pXcG9zW3q9SEJpVXgeD-WwQgzLpmFcbXPhLg,5492
25
- meridian/analysis/templates/style.scss,sha256=nSrZOpcIrVyiL4eC9jLUlxIZtAKZ0Rt8pwfk4H1nMrs,5076
26
- meridian/analysis/templates/summary.html.jinja,sha256=LuENVDHYIpNo4pzloYaCR2K9XN1Ow6_9oQOcOwD9nGg,1707
27
- meridian/analysis/templates/table.html.jinja,sha256=mvLMZx92RcD2JAS2w2eZtfYG-6WdfwYVo7pM8TbHp4g,1176
28
- meridian/backend/__init__.py,sha256=ftXcdb3tIky_m8exhD9RRhaEqTEvMcqZ8lGkkR1PjsE,39495
29
- meridian/backend/config.py,sha256=B9VQnhBfg9RW04GNbt7F5uCugByenoJzt-keFLLYEp8,3561
30
- meridian/backend/test_utils.py,sha256=DYU5IpWiyM26aTY9Q84mOGRw0dQ9XmsZRsAJNFuZDp0,11667
31
- meridian/data/__init__.py,sha256=StIe-wfYnnbfUbKtZHwnAQcRQUS8XCZk_PCaEzw90Ww,929
32
- meridian/data/arg_builder.py,sha256=Kqlt88bOqFj6D3xNwvWo4MBwNwcDFHzd-wMfEOmLoPU,3741
33
- meridian/data/data_frame_input_data_builder.py,sha256=_hexZMFAuAowgo6FaOGElHSFHqhGnHQwEEBcwnT3zUE,27295
34
- meridian/data/input_data.py,sha256=Qlxm4El6h1SRPsWDqZoKkOcMtrjiRWr3z8sU2mtghRA,43151
35
- meridian/data/input_data_builder.py,sha256=tbZjVXPDfmtndVyJA0fmzGzZwZb0RCEjXOTXb-ga8Nc,25648
36
- meridian/data/load.py,sha256=X2nmYCC-7A0RUgmdolTqCt0TD3NEZabQ5oGv-TugE00,40129
37
- meridian/data/nd_array_input_data_builder.py,sha256=lfpmnENGuSGKyUd7bDGAwoLqHqteOKmHdKl0VI2wCQA,16341
38
- meridian/data/test_utils.py,sha256=mw-QPTP15oXf32I7cxMe8iSFBLB3seqEiITZMTz_Eg8,59838
39
- meridian/data/time_coordinates.py,sha256=C5A5fscSLjPH6G9YT8OspgIlCrkMY7y8dMFEt3tNSnE,9874
40
- meridian/mlflow/__init__.py,sha256=elwXUqPQYi7VF9PYjelU1tydfcUrmtuoq6eJCOnV9bk,693
41
- meridian/mlflow/autolog.py,sha256=SZsrynLjozcyrAFCNWiqchSa2yOszVnwFBGz23BmWUU,6379
42
- meridian/model/__init__.py,sha256=mhF5VkRxvwamRa_0AihgbFuXLMueRCK-Je_ZZvU5IFw,1013
43
- meridian/model/adstock_hill.py,sha256=HoRKjyL03pCTBz6Utof9wEvlQCFM43BvrEW_oupj7NU,17688
44
- meridian/model/knots.py,sha256=87kw5oa3T1k9GgT_aWXTqQx5XCxLsS2w1hnzc581XL0,26677
45
- meridian/model/media.py,sha256=skjy4Vd8LfDQWlqR_2lJ1qbG9UcS1dow5W45BAu4qk8,14599
46
- meridian/model/model.py,sha256=jMtfl7woWtJ8M8AX42QeZ5hUS8hlhPdZ-9OU8KahjKA,68984
47
- meridian/model/model_test_data.py,sha256=XGBz8RGdCsjAUOmgxX3CfWSj-_hdq2Lc8saFCqmImwM,23901
48
- meridian/model/posterior_sampler.py,sha256=f3MayglIgBeBjWeXJU_RgT9cCugcjJ3aEjHqaWPsTbg,26806
49
- meridian/model/prior_distribution.py,sha256=ZArW4uXIPPQL6hRWiGZUzcHktbkjE_vOklvlbp9LR64,57662
50
- meridian/model/prior_sampler.py,sha256=iLvCefhA4WY0ENcnLK9471WUZPPyzQ1je58MRjxKv74,25460
51
- meridian/model/spec.py,sha256=VlK6WJiPo2lzOF0O2judtJ6O3uEw7wYL5AT8bioq4gE,19188
52
- meridian/model/transformers.py,sha256=HxlVJitxP-wu-NOHU0tArFUZ4NAO3c7adAYj4Zvqnvo,8363
53
- meridian/model/eda/__init__.py,sha256=w3p7ZUZLq5TOEHm8n2P1CWjGrzuNrkqSSnVFdlw17Dk,812
54
- meridian/model/eda/constants.py,sha256=V9aOHQDvB3WAEyT0NE4gE8rqbStaGVh3XDlBPOKpuLc,739
55
- meridian/model/eda/eda_engine.py,sha256=5Ikgiz-6d3uTBan71WwsgPHOqk0fAy390ZLCq9L6HoY,64846
56
- meridian/model/eda/eda_outcome.py,sha256=P-0kNIbNXcyqMaNvFxiL3x6fhtYOL2trw-zPPZGXh5w,5670
57
- meridian/model/eda/eda_spec.py,sha256=diieYyZH0ee3ZLy0rGFMcWrrgiUrz2HctMwOrmtJR6w,2871
58
- meridian/model/eda/meridian_eda.py,sha256=GTdBaAtfsHS5s6P5ZESaeh1ElKV_o7dSqQosiMnFBKg,7537
59
- schema/__init__.py,sha256=Df2XKjMKa0ry7CTlDuJnyxuTdSgAd5za922wMlE98cg,681
60
- schema/serde/__init__.py,sha256=xyydIcWB5IUpcn3wu1m9HL1fK4gMWURbwTyRsQtolF0,975
61
- schema/serde/constants.py,sha256=aYtD_RuA0GCkpC4TIQq3VjMqEc837Wn-TlJNm-yn_4Y,1842
62
- schema/serde/distribution.py,sha256=jy3h6JD1TSs4gwociMis814sz_Fm2kFQ2UbkgjYJW9k,19347
63
- schema/serde/eda_spec.py,sha256=uOqBeZpUU3Dzzc19rU1LjHWmUhRmVcx8oIZvZfVJHT8,7180
64
- schema/serde/function_registry.py,sha256=GbgC5_9NDcA9Y7nqmdJ-4-LK5JPhhfI50Lmfy5ZBJOg,4858
65
- schema/serde/hyperparameters.py,sha256=Igm-PZmIozrsKZH6c-XkrU_Nlf8OAuxpnJJfv7W1SfQ,13524
66
- schema/serde/inference_data.py,sha256=DrwE9hU8LMrl0z8W_sUSIaPrRdym_lu0iOqpT4KZxsA,3623
67
- schema/serde/marketing_data.py,sha256=yb-fRTe84Sjg7-v3wsvYRRXvrxLSFWSenO0_ikMvUpk,44845
68
- schema/serde/meridian_serde.py,sha256=ZG05JaBG4LW8mhl-Cunje9Q6xyR4tyNTtLYedzMBYjA,15985
69
- schema/serde/serde.py,sha256=8vUqhJxvZgX9UY3rXTyWJznRgapwDzzaHXDHwV_kKTA,1612
70
- schema/serde/test_data.py,sha256=7hfEWyvZ9WcAkVAOXt6elX8stJlsfhfd-ASlHo9SRb8,107342
71
- schema/utils/__init__.py,sha256=AkC4NMbmXC3PFBY9dFYxlf3qFsxt5OOBVdc9zmFXsC8,675
72
- schema/utils/time_record.py,sha256=-KzHFjvSBUUXsfESPAfcJP_VFxaFLqj90Ac0kgKWfpI,4624
73
- google_meridian-1.3.1.dist-info/METADATA,sha256=wu5D6r6v46vd5g4uKLfXEVuhxkO3jwEgS68wn6m0jR4,9547
74
- google_meridian-1.3.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
75
- google_meridian-1.3.1.dist-info/top_level.txt,sha256=yWkWDLV_UUanhKmk_xNPiKNdPDl1oyU1sBYwEnhaSf4,16
76
- google_meridian-1.3.1.dist-info/RECORD,,