google-meridian 1.1.5__py3-none-any.whl → 1.2.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.
- {google_meridian-1.1.5.dist-info → google_meridian-1.2.0.dist-info}/METADATA +8 -2
- google_meridian-1.2.0.dist-info/RECORD +52 -0
- meridian/__init__.py +1 -0
- meridian/analysis/analyzer.py +526 -362
- meridian/analysis/optimizer.py +275 -267
- meridian/analysis/test_utils.py +96 -94
- meridian/analysis/visualizer.py +37 -49
- meridian/backend/__init__.py +514 -0
- meridian/backend/config.py +59 -0
- meridian/backend/test_utils.py +95 -0
- meridian/constants.py +59 -3
- meridian/data/input_data.py +94 -0
- meridian/data/test_utils.py +144 -12
- meridian/model/adstock_hill.py +279 -33
- meridian/model/eda/__init__.py +17 -0
- meridian/model/eda/eda_engine.py +306 -0
- meridian/model/knots.py +525 -2
- meridian/model/media.py +62 -54
- meridian/model/model.py +224 -97
- meridian/model/model_test_data.py +323 -157
- meridian/model/posterior_sampler.py +84 -77
- meridian/model/prior_distribution.py +538 -168
- meridian/model/prior_sampler.py +65 -65
- meridian/model/spec.py +23 -3
- meridian/model/transformers.py +53 -47
- meridian/version.py +1 -1
- google_meridian-1.1.5.dist-info/RECORD +0 -47
- {google_meridian-1.1.5.dist-info → google_meridian-1.2.0.dist-info}/WHEEL +0 -0
- {google_meridian-1.1.5.dist-info → google_meridian-1.2.0.dist-info}/licenses/LICENSE +0 -0
- {google_meridian-1.1.5.dist-info → google_meridian-1.2.0.dist-info}/top_level.txt +0 -0
meridian/model/media.py
CHANGED
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
"""Structures and functions for manipulating media value data and tensors."""
|
|
16
16
|
|
|
17
17
|
import dataclasses
|
|
18
|
+
from meridian import backend
|
|
18
19
|
from meridian import constants
|
|
19
20
|
from meridian.data import input_data as data
|
|
20
21
|
from meridian.model import spec
|
|
21
22
|
from meridian.model import transformers
|
|
22
|
-
import tensorflow as tf
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
__all__ = [
|
|
@@ -35,9 +35,9 @@ __all__ = [
|
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
def _roi_calibration_scaled_counterfactual(
|
|
38
|
-
metric_scaled:
|
|
39
|
-
calibration_period:
|
|
40
|
-
) ->
|
|
38
|
+
metric_scaled: backend.Tensor,
|
|
39
|
+
calibration_period: backend.Tensor,
|
|
40
|
+
) -> backend.Tensor:
|
|
41
41
|
"""Calculate ROI calibration scaled counterfactual media or reach.
|
|
42
42
|
|
|
43
43
|
Args:
|
|
@@ -50,8 +50,8 @@ def _roi_calibration_scaled_counterfactual(
|
|
|
50
50
|
A tensor of scaled metric values with shape `(n_geos, n_times, n_channels)`
|
|
51
51
|
where media values are set to zero during the calibration period.
|
|
52
52
|
"""
|
|
53
|
-
factors =
|
|
54
|
-
return
|
|
53
|
+
factors = backend.where(calibration_period, 0.0, 1.0)
|
|
54
|
+
return backend.einsum("gtm,tm->gtm", metric_scaled, factors)
|
|
55
55
|
|
|
56
56
|
|
|
57
57
|
@dataclasses.dataclass(frozen=True)
|
|
@@ -84,12 +84,12 @@ class MediaTensors:
|
|
|
84
84
|
(repeated for each channel.)
|
|
85
85
|
"""
|
|
86
86
|
|
|
87
|
-
media:
|
|
88
|
-
media_spend:
|
|
87
|
+
media: backend.Tensor | None = None
|
|
88
|
+
media_spend: backend.Tensor | None = None
|
|
89
89
|
media_transformer: transformers.MediaTransformer | None = None
|
|
90
|
-
media_scaled:
|
|
91
|
-
prior_media_scaled_counterfactual:
|
|
92
|
-
prior_denominator:
|
|
90
|
+
media_scaled: backend.Tensor | None = None
|
|
91
|
+
prior_media_scaled_counterfactual: backend.Tensor | None = None
|
|
92
|
+
prior_denominator: backend.Tensor | None = None
|
|
93
93
|
|
|
94
94
|
|
|
95
95
|
def build_media_tensors(
|
|
@@ -101,26 +101,24 @@ def build_media_tensors(
|
|
|
101
101
|
return MediaTensors()
|
|
102
102
|
|
|
103
103
|
# Derive and set media tensors from media values in the input data.
|
|
104
|
-
media =
|
|
105
|
-
media_spend =
|
|
104
|
+
media = backend.to_tensor(input_data.media, dtype=backend.float32)
|
|
105
|
+
media_spend = backend.to_tensor(input_data.media_spend, dtype=backend.float32)
|
|
106
106
|
media_transformer = transformers.MediaTransformer(
|
|
107
|
-
media,
|
|
107
|
+
media, backend.to_tensor(input_data.population, dtype=backend.float32)
|
|
108
108
|
)
|
|
109
109
|
media_scaled = media_transformer.forward(media)
|
|
110
110
|
prior_type = model_spec.effective_media_prior_type
|
|
111
111
|
calibration_period = model_spec.roi_calibration_period
|
|
112
112
|
if calibration_period is not None:
|
|
113
|
-
|
|
114
|
-
calibration_period, dtype=
|
|
113
|
+
calibration_period_tensor = backend.to_tensor(
|
|
114
|
+
calibration_period, dtype=backend.bool_
|
|
115
115
|
)
|
|
116
116
|
else:
|
|
117
|
-
|
|
117
|
+
calibration_period_tensor = None
|
|
118
118
|
|
|
119
|
-
aggregated_media_spend =
|
|
120
|
-
input_data.aggregate_media_spend(
|
|
121
|
-
|
|
122
|
-
),
|
|
123
|
-
dtype=tf.float32,
|
|
119
|
+
aggregated_media_spend = backend.to_tensor(
|
|
120
|
+
input_data.aggregate_media_spend(calibration_period=calibration_period),
|
|
121
|
+
dtype=backend.float32,
|
|
124
122
|
)
|
|
125
123
|
# Set `prior_media_scaled_counterfactual` and `prior_denominator` depending on
|
|
126
124
|
# the prior type.
|
|
@@ -133,7 +131,7 @@ def build_media_tensors(
|
|
|
133
131
|
prior_media_scaled_counterfactual = (
|
|
134
132
|
_roi_calibration_scaled_counterfactual(
|
|
135
133
|
media_scaled,
|
|
136
|
-
calibration_period=
|
|
134
|
+
calibration_period=calibration_period_tensor,
|
|
137
135
|
)
|
|
138
136
|
)
|
|
139
137
|
elif prior_type == constants.TREATMENT_PRIOR_TYPE_MROI:
|
|
@@ -141,8 +139,12 @@ def build_media_tensors(
|
|
|
141
139
|
prior_denominator = aggregated_media_spend * (constants.MROI_FACTOR - 1.0)
|
|
142
140
|
elif prior_type == constants.TREATMENT_PRIOR_TYPE_CONTRIBUTION:
|
|
143
141
|
prior_media_scaled_counterfactual = None
|
|
144
|
-
total_outcome =
|
|
145
|
-
|
|
142
|
+
total_outcome = backend.to_tensor(
|
|
143
|
+
input_data.get_total_outcome(), dtype=backend.float32
|
|
144
|
+
)
|
|
145
|
+
prior_denominator = backend.repeat(
|
|
146
|
+
total_outcome, len(input_data.media_channel)
|
|
147
|
+
)
|
|
146
148
|
elif prior_type == constants.TREATMENT_PRIOR_TYPE_COEFFICIENT:
|
|
147
149
|
prior_media_scaled_counterfactual = None
|
|
148
150
|
prior_denominator = None
|
|
@@ -171,9 +173,9 @@ class OrganicMediaTensors:
|
|
|
171
173
|
by the median value.
|
|
172
174
|
"""
|
|
173
175
|
|
|
174
|
-
organic_media:
|
|
176
|
+
organic_media: backend.Tensor | None = None
|
|
175
177
|
organic_media_transformer: transformers.MediaTransformer | None = None
|
|
176
|
-
organic_media_scaled:
|
|
178
|
+
organic_media_scaled: backend.Tensor | None = None
|
|
177
179
|
|
|
178
180
|
|
|
179
181
|
def build_organic_media_tensors(
|
|
@@ -184,12 +186,12 @@ def build_organic_media_tensors(
|
|
|
184
186
|
return OrganicMediaTensors()
|
|
185
187
|
|
|
186
188
|
# Derive and set media tensors from media values in the input data.
|
|
187
|
-
organic_media =
|
|
188
|
-
input_data.organic_media, dtype=
|
|
189
|
+
organic_media = backend.to_tensor(
|
|
190
|
+
input_data.organic_media, dtype=backend.float32
|
|
189
191
|
)
|
|
190
192
|
organic_media_transformer = transformers.MediaTransformer(
|
|
191
193
|
organic_media,
|
|
192
|
-
|
|
194
|
+
backend.to_tensor(input_data.population, dtype=backend.float32),
|
|
193
195
|
)
|
|
194
196
|
organic_media_scaled = organic_media_transformer.forward(organic_media)
|
|
195
197
|
|
|
@@ -233,14 +235,14 @@ class RfTensors:
|
|
|
233
235
|
(repeated for each channel).
|
|
234
236
|
"""
|
|
235
237
|
|
|
236
|
-
reach:
|
|
237
|
-
frequency:
|
|
238
|
-
rf_impressions:
|
|
239
|
-
rf_spend:
|
|
238
|
+
reach: backend.Tensor | None = None
|
|
239
|
+
frequency: backend.Tensor | None = None
|
|
240
|
+
rf_impressions: backend.Tensor | None = None
|
|
241
|
+
rf_spend: backend.Tensor | None = None
|
|
240
242
|
reach_transformer: transformers.MediaTransformer | None = None
|
|
241
|
-
reach_scaled:
|
|
242
|
-
prior_reach_scaled_counterfactual:
|
|
243
|
-
prior_denominator:
|
|
243
|
+
reach_scaled: backend.Tensor | None = None
|
|
244
|
+
prior_reach_scaled_counterfactual: backend.Tensor | None = None
|
|
245
|
+
prior_denominator: backend.Tensor | None = None
|
|
244
246
|
|
|
245
247
|
|
|
246
248
|
def build_rf_tensors(
|
|
@@ -251,23 +253,25 @@ def build_rf_tensors(
|
|
|
251
253
|
if input_data.reach is None:
|
|
252
254
|
return RfTensors()
|
|
253
255
|
|
|
254
|
-
reach =
|
|
255
|
-
frequency =
|
|
256
|
+
reach = backend.to_tensor(input_data.reach, dtype=backend.float32)
|
|
257
|
+
frequency = backend.to_tensor(input_data.frequency, dtype=backend.float32)
|
|
256
258
|
rf_impressions = (
|
|
257
259
|
reach * frequency if reach is not None and frequency is not None else None
|
|
258
260
|
)
|
|
259
|
-
rf_spend =
|
|
261
|
+
rf_spend = backend.to_tensor(input_data.rf_spend, dtype=backend.float32)
|
|
260
262
|
reach_transformer = transformers.MediaTransformer(
|
|
261
|
-
reach,
|
|
263
|
+
reach, backend.to_tensor(input_data.population, dtype=backend.float32)
|
|
262
264
|
)
|
|
263
265
|
reach_scaled = reach_transformer.forward(reach)
|
|
264
266
|
prior_type = model_spec.effective_rf_prior_type
|
|
265
267
|
calibration_period = model_spec.rf_roi_calibration_period
|
|
266
268
|
if calibration_period is not None:
|
|
267
|
-
calibration_period =
|
|
268
|
-
|
|
269
|
+
calibration_period = backend.to_tensor(
|
|
270
|
+
calibration_period, dtype=backend.bool_
|
|
271
|
+
)
|
|
272
|
+
aggregated_rf_spend = backend.to_tensor(
|
|
269
273
|
input_data.aggregate_rf_spend(calibration_period=calibration_period),
|
|
270
|
-
dtype=
|
|
274
|
+
dtype=backend.float32,
|
|
271
275
|
)
|
|
272
276
|
# Set `prior_reach_scaled_counterfactual` and `prior_denominator` depending on
|
|
273
277
|
# the prior type.
|
|
@@ -287,8 +291,12 @@ def build_rf_tensors(
|
|
|
287
291
|
prior_denominator = aggregated_rf_spend * (constants.MROI_FACTOR - 1.0)
|
|
288
292
|
elif prior_type == constants.TREATMENT_PRIOR_TYPE_CONTRIBUTION:
|
|
289
293
|
prior_reach_scaled_counterfactual = None
|
|
290
|
-
total_outcome =
|
|
291
|
-
|
|
294
|
+
total_outcome = backend.to_tensor(
|
|
295
|
+
input_data.get_total_outcome(), dtype=backend.float32
|
|
296
|
+
)
|
|
297
|
+
prior_denominator = backend.repeat(
|
|
298
|
+
total_outcome, len(input_data.rf_channel)
|
|
299
|
+
)
|
|
292
300
|
elif prior_type == constants.TREATMENT_PRIOR_TYPE_COEFFICIENT:
|
|
293
301
|
prior_reach_scaled_counterfactual = None
|
|
294
302
|
prior_denominator = None
|
|
@@ -320,10 +328,10 @@ class OrganicRfTensors:
|
|
|
320
328
|
by the median value.
|
|
321
329
|
"""
|
|
322
330
|
|
|
323
|
-
organic_reach:
|
|
324
|
-
organic_frequency:
|
|
331
|
+
organic_reach: backend.Tensor | None = None
|
|
332
|
+
organic_frequency: backend.Tensor | None = None
|
|
325
333
|
organic_reach_transformer: transformers.MediaTransformer | None = None
|
|
326
|
-
organic_reach_scaled:
|
|
334
|
+
organic_reach_scaled: backend.Tensor | None = None
|
|
327
335
|
|
|
328
336
|
|
|
329
337
|
def build_organic_rf_tensors(
|
|
@@ -333,15 +341,15 @@ def build_organic_rf_tensors(
|
|
|
333
341
|
if input_data.organic_reach is None:
|
|
334
342
|
return OrganicRfTensors()
|
|
335
343
|
|
|
336
|
-
organic_reach =
|
|
337
|
-
input_data.organic_reach, dtype=
|
|
344
|
+
organic_reach = backend.to_tensor(
|
|
345
|
+
input_data.organic_reach, dtype=backend.float32
|
|
338
346
|
)
|
|
339
|
-
organic_frequency =
|
|
340
|
-
input_data.organic_frequency, dtype=
|
|
347
|
+
organic_frequency = backend.to_tensor(
|
|
348
|
+
input_data.organic_frequency, dtype=backend.float32
|
|
341
349
|
)
|
|
342
350
|
organic_reach_transformer = transformers.MediaTransformer(
|
|
343
351
|
organic_reach,
|
|
344
|
-
|
|
352
|
+
backend.to_tensor(input_data.population, dtype=backend.float32),
|
|
345
353
|
)
|
|
346
354
|
organic_reach_scaled = organic_reach_transformer.forward(organic_reach)
|
|
347
355
|
|