google-meridian 1.0.9__py3-none-any.whl → 1.1.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.0.9.dist-info → google_meridian-1.1.0.dist-info}/METADATA +2 -2
- google_meridian-1.1.0.dist-info/RECORD +41 -0
- {google_meridian-1.0.9.dist-info → google_meridian-1.1.0.dist-info}/WHEEL +1 -1
- meridian/__init__.py +1 -1
- meridian/analysis/analyzer.py +195 -189
- meridian/analysis/optimizer.py +263 -65
- meridian/analysis/summarizer.py +4 -4
- meridian/analysis/test_utils.py +81 -81
- meridian/analysis/visualizer.py +12 -16
- meridian/constants.py +100 -16
- meridian/data/input_data.py +115 -19
- meridian/data/test_utils.py +116 -5
- meridian/data/time_coordinates.py +3 -3
- meridian/model/media.py +133 -98
- meridian/model/model.py +447 -57
- meridian/model/model_test_data.py +11 -0
- meridian/model/posterior_sampler.py +120 -43
- meridian/model/prior_distribution.py +96 -51
- meridian/model/prior_sampler.py +179 -209
- meridian/model/spec.py +196 -36
- meridian/model/transformers.py +15 -3
- google_meridian-1.0.9.dist-info/RECORD +0 -41
- {google_meridian-1.0.9.dist-info → google_meridian-1.1.0.dist-info}/licenses/LICENSE +0 -0
- {google_meridian-1.0.9.dist-info → google_meridian-1.1.0.dist-info}/top_level.txt +0 -0
meridian/model/media.py
CHANGED
|
@@ -34,9 +34,29 @@ __all__ = [
|
|
|
34
34
|
]
|
|
35
35
|
|
|
36
36
|
|
|
37
|
+
def _roi_calibration_scaled_counterfactual(
|
|
38
|
+
metric_scaled: tf.Tensor,
|
|
39
|
+
calibration_period: tf.Tensor,
|
|
40
|
+
) -> tf.Tensor:
|
|
41
|
+
"""Calculate ROI calibration scaled counterfactual media or reach.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
metric_scaled: A tensor of scaled metric values with shape `(n_geos,
|
|
45
|
+
n_times, n_channels)`.
|
|
46
|
+
calibration_period: A boolean tensor indicating which time periods are used
|
|
47
|
+
for calculation.
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
A tensor of scaled metric values with shape `(n_geos, n_times, n_channels)`
|
|
51
|
+
where media values are set to zero during the calibration period.
|
|
52
|
+
"""
|
|
53
|
+
factors = tf.where(calibration_period, 0.0, 1.0)
|
|
54
|
+
return tf.einsum("gtm,tm->gtm", metric_scaled, factors)
|
|
55
|
+
|
|
56
|
+
|
|
37
57
|
@dataclasses.dataclass(frozen=True)
|
|
38
58
|
class MediaTensors:
|
|
39
|
-
"""Container for media tensors.
|
|
59
|
+
"""Container for (paid) media tensors.
|
|
40
60
|
|
|
41
61
|
Attributes:
|
|
42
62
|
media: A tensor constructed from `InputData.media`.
|
|
@@ -45,25 +65,31 @@ class MediaTensors:
|
|
|
45
65
|
model's media data.
|
|
46
66
|
media_scaled: The media tensor normalized by population and by the median
|
|
47
67
|
value.
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
68
|
+
prior_media_scaled_counterfactual: A tensor containing `media_scaled` values
|
|
69
|
+
corresponding to the counterfactual scenario required for the prior
|
|
70
|
+
calculation. For ROI priors, the counterfactual scenario is where media is
|
|
71
|
+
set to zero during the calibration period. For mROI priors, the
|
|
72
|
+
counterfactual scenario is where media is increased by a small factor for
|
|
73
|
+
all `n_media_times`. For contribution priors, the counterfactual scenario
|
|
74
|
+
is where media is set to zero for all `n_media_times`. This attribute is
|
|
75
|
+
set to `None` when it would otherwise be a tensor of zeros, i.e., when
|
|
76
|
+
contribution contribution priors are used, or when ROI priors are used and
|
|
77
|
+
`roi_calibration_period` is `None`.
|
|
78
|
+
prior_denominator: If ROI, mROI, or contribution priors are used, this
|
|
79
|
+
represents the denominator. It is a tensor with dimension equal to
|
|
80
|
+
`n_media_channels`. For ROI priors, it is the spend during the overlapping
|
|
81
|
+
time periods between the calibration period and the modeling time window.
|
|
82
|
+
For mROI priors, it is the ROI prior denominator multiplied by a small
|
|
83
|
+
factor. For contribution priors, it is the total observed outcome
|
|
84
|
+
(repeated for each channel.)
|
|
58
85
|
"""
|
|
59
86
|
|
|
60
87
|
media: tf.Tensor | None = None
|
|
61
88
|
media_spend: tf.Tensor | None = None
|
|
62
89
|
media_transformer: transformers.MediaTransformer | None = None
|
|
63
90
|
media_scaled: tf.Tensor | None = None
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
media_spend_counterfactual: tf.Tensor | None = None
|
|
91
|
+
prior_media_scaled_counterfactual: tf.Tensor | None = None
|
|
92
|
+
prior_denominator: tf.Tensor | None = None
|
|
67
93
|
|
|
68
94
|
|
|
69
95
|
def build_media_tensors(
|
|
@@ -81,43 +107,55 @@ def build_media_tensors(
|
|
|
81
107
|
media, tf.convert_to_tensor(input_data.population, dtype=tf.float32)
|
|
82
108
|
)
|
|
83
109
|
media_scaled = media_transformer.forward(media)
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
):
|
|
91
|
-
factor = constants.MROI_FACTOR
|
|
110
|
+
prior_type = model_spec.effective_media_prior_type
|
|
111
|
+
calibration_period = model_spec.roi_calibration_period
|
|
112
|
+
if calibration_period is not None:
|
|
113
|
+
calibration_period_tf = tf.convert_to_tensor(
|
|
114
|
+
calibration_period, dtype=tf.bool
|
|
115
|
+
)
|
|
92
116
|
else:
|
|
93
|
-
|
|
117
|
+
calibration_period_tf = None
|
|
94
118
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
119
|
+
aggregated_media_spend = tf.convert_to_tensor(
|
|
120
|
+
input_data.aggregate_media_spend(
|
|
121
|
+
calibration_period=calibration_period
|
|
122
|
+
),
|
|
123
|
+
dtype=tf.float32,
|
|
124
|
+
)
|
|
125
|
+
# Set `prior_media_scaled_counterfactual` and `prior_denominator` depending on
|
|
126
|
+
# the prior type.
|
|
127
|
+
if prior_type == constants.TREATMENT_PRIOR_TYPE_ROI:
|
|
128
|
+
prior_denominator = aggregated_media_spend
|
|
129
|
+
|
|
130
|
+
if calibration_period is None:
|
|
131
|
+
prior_media_scaled_counterfactual = None
|
|
132
|
+
else:
|
|
133
|
+
prior_media_scaled_counterfactual = (
|
|
134
|
+
_roi_calibration_scaled_counterfactual(
|
|
135
|
+
media_scaled,
|
|
136
|
+
calibration_period=calibration_period_tf,
|
|
137
|
+
)
|
|
138
|
+
)
|
|
139
|
+
elif prior_type == constants.TREATMENT_PRIOR_TYPE_MROI:
|
|
140
|
+
prior_media_scaled_counterfactual = media_scaled * constants.MROI_FACTOR
|
|
141
|
+
prior_denominator = aggregated_media_spend * (constants.MROI_FACTOR - 1.0)
|
|
142
|
+
elif prior_type == constants.TREATMENT_PRIOR_TYPE_CONTRIBUTION:
|
|
143
|
+
prior_media_scaled_counterfactual = None
|
|
144
|
+
total_outcome = tf.cast(input_data.get_total_outcome(), tf.float32)
|
|
145
|
+
prior_denominator = tf.repeat(total_outcome, len(input_data.media_channel))
|
|
146
|
+
elif prior_type == constants.TREATMENT_PRIOR_TYPE_COEFFICIENT:
|
|
147
|
+
prior_media_scaled_counterfactual = None
|
|
148
|
+
prior_denominator = None
|
|
99
149
|
else:
|
|
100
|
-
|
|
101
|
-
model_spec.roi_calibration_period, factor * media, media
|
|
102
|
-
)
|
|
103
|
-
media_counterfactual_scaled = tf.where(
|
|
104
|
-
model_spec.roi_calibration_period, factor * media_scaled, media_scaled
|
|
105
|
-
)
|
|
106
|
-
n_times = len(input_data.time)
|
|
107
|
-
media_spend_counterfactual = tf.where(
|
|
108
|
-
model_spec.roi_calibration_period[..., -n_times:, :],
|
|
109
|
-
factor * media_spend,
|
|
110
|
-
media_spend,
|
|
111
|
-
)
|
|
150
|
+
raise ValueError(f"Unsupported prior type: {prior_type}")
|
|
112
151
|
|
|
113
152
|
return MediaTensors(
|
|
114
153
|
media=media,
|
|
115
154
|
media_spend=media_spend,
|
|
116
155
|
media_transformer=media_transformer,
|
|
117
156
|
media_scaled=media_scaled,
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
media_spend_counterfactual=media_spend_counterfactual,
|
|
157
|
+
prior_media_scaled_counterfactual=prior_media_scaled_counterfactual,
|
|
158
|
+
prior_denominator=prior_denominator,
|
|
121
159
|
)
|
|
122
160
|
|
|
123
161
|
|
|
@@ -131,17 +169,11 @@ class OrganicMediaTensors:
|
|
|
131
169
|
the model's organic media data.
|
|
132
170
|
organic_media_scaled: The organic media tensor normalized by population and
|
|
133
171
|
by the median value.
|
|
134
|
-
organic_media_counterfactual: A tensor containing the organic media
|
|
135
|
-
counterfactual values.
|
|
136
|
-
organic_media_counterfactual_scaled: A tensor containing the organic media
|
|
137
|
-
counterfactual scaled values.
|
|
138
172
|
"""
|
|
139
173
|
|
|
140
174
|
organic_media: tf.Tensor | None = None
|
|
141
175
|
organic_media_transformer: transformers.MediaTransformer | None = None
|
|
142
176
|
organic_media_scaled: tf.Tensor | None = None
|
|
143
|
-
organic_media_counterfactual: tf.Tensor | None = None
|
|
144
|
-
organic_media_counterfactual_scaled: tf.Tensor | None = None
|
|
145
177
|
|
|
146
178
|
|
|
147
179
|
def build_organic_media_tensors(
|
|
@@ -160,15 +192,11 @@ def build_organic_media_tensors(
|
|
|
160
192
|
tf.convert_to_tensor(input_data.population, dtype=tf.float32),
|
|
161
193
|
)
|
|
162
194
|
organic_media_scaled = organic_media_transformer.forward(organic_media)
|
|
163
|
-
organic_media_counterfactual = tf.zeros_like(organic_media)
|
|
164
|
-
organic_media_counterfactual_scaled = tf.zeros_like(organic_media_scaled)
|
|
165
195
|
|
|
166
196
|
return OrganicMediaTensors(
|
|
167
197
|
organic_media=organic_media,
|
|
168
198
|
organic_media_transformer=organic_media_transformer,
|
|
169
199
|
organic_media_scaled=organic_media_scaled,
|
|
170
|
-
organic_media_counterfactual=organic_media_counterfactual,
|
|
171
|
-
organic_media_counterfactual_scaled=organic_media_counterfactual_scaled,
|
|
172
200
|
)
|
|
173
201
|
|
|
174
202
|
|
|
@@ -184,16 +212,23 @@ class RfTensors:
|
|
|
184
212
|
model's RF data.
|
|
185
213
|
reach_scaled: A reach tensor normalized by population and by the median
|
|
186
214
|
value.
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
`
|
|
215
|
+
prior_reach_scaled_counterfactual: A tensor containing `reach_scaled` values
|
|
216
|
+
corresponding to the counterfactual scenario required for the prior
|
|
217
|
+
calculation. For ROI priors, the counterfactual scenario is where reach is
|
|
218
|
+
set to zero during the calibration period. For mROI priors, the
|
|
219
|
+
counterfactual scenario is where reach is increased by a small factor for
|
|
220
|
+
all `n_rf_times`. For contribution priors, the counterfactual scenario is
|
|
221
|
+
where reach is set to zero for all `n_rf_times`. This attribute is set to
|
|
222
|
+
`None` when it would otherwise be a tensor of zeros, i.e., when
|
|
223
|
+
contribution contribution priors are used, or when ROI priors are used and
|
|
224
|
+
`rf_roi_calibration_period` is `None`.
|
|
225
|
+
prior_denominator: If ROI, mROI, or contribution priors are used, this
|
|
226
|
+
represents the denominator. It is a tensor with dimension equal to
|
|
227
|
+
`n_rf_channels`. For ROI priors, it is the spend during the overlapping
|
|
228
|
+
time periods between the calibration period and the modeling time window.
|
|
229
|
+
For mROI priors, it is the ROI prior denominator multiplied by a small
|
|
230
|
+
factor. For contribution priors, it is the total observed outcome
|
|
231
|
+
(repeated for each channel).
|
|
197
232
|
"""
|
|
198
233
|
|
|
199
234
|
reach: tf.Tensor | None = None
|
|
@@ -201,9 +236,8 @@ class RfTensors:
|
|
|
201
236
|
rf_spend: tf.Tensor | None = None
|
|
202
237
|
reach_transformer: transformers.MediaTransformer | None = None
|
|
203
238
|
reach_scaled: tf.Tensor | None = None
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
rf_spend_counterfactual: tf.Tensor | None = None
|
|
239
|
+
prior_reach_scaled_counterfactual: tf.Tensor | None = None
|
|
240
|
+
prior_denominator: tf.Tensor | None = None
|
|
207
241
|
|
|
208
242
|
|
|
209
243
|
def build_rf_tensors(
|
|
@@ -221,27 +255,39 @@ def build_rf_tensors(
|
|
|
221
255
|
reach, tf.convert_to_tensor(input_data.population, dtype=tf.float32)
|
|
222
256
|
)
|
|
223
257
|
reach_scaled = reach_transformer.forward(reach)
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
258
|
+
prior_type = model_spec.effective_rf_prior_type
|
|
259
|
+
calibration_period = model_spec.rf_roi_calibration_period
|
|
260
|
+
if calibration_period is not None:
|
|
261
|
+
calibration_period = tf.convert_to_tensor(calibration_period, dtype=tf.bool)
|
|
262
|
+
aggregated_rf_spend = tf.convert_to_tensor(
|
|
263
|
+
input_data.aggregate_rf_spend(calibration_period=calibration_period),
|
|
264
|
+
dtype=tf.float32,
|
|
265
|
+
)
|
|
266
|
+
# Set `prior_reach_scaled_counterfactual` and `prior_denominator` depending on
|
|
267
|
+
# the prior type.
|
|
268
|
+
if prior_type == constants.TREATMENT_PRIOR_TYPE_ROI:
|
|
269
|
+
prior_denominator = aggregated_rf_spend
|
|
270
|
+
if calibration_period is None:
|
|
271
|
+
prior_reach_scaled_counterfactual = None
|
|
272
|
+
else:
|
|
273
|
+
prior_reach_scaled_counterfactual = (
|
|
274
|
+
_roi_calibration_scaled_counterfactual(
|
|
275
|
+
reach_scaled,
|
|
276
|
+
calibration_period=calibration_period,
|
|
277
|
+
)
|
|
278
|
+
)
|
|
279
|
+
elif prior_type == constants.TREATMENT_PRIOR_TYPE_MROI:
|
|
280
|
+
prior_reach_scaled_counterfactual = reach_scaled * constants.MROI_FACTOR
|
|
281
|
+
prior_denominator = aggregated_rf_spend * (constants.MROI_FACTOR - 1.0)
|
|
282
|
+
elif prior_type == constants.TREATMENT_PRIOR_TYPE_CONTRIBUTION:
|
|
283
|
+
prior_reach_scaled_counterfactual = None
|
|
284
|
+
total_outcome = tf.cast(input_data.get_total_outcome(), tf.float32)
|
|
285
|
+
prior_denominator = tf.repeat(total_outcome, len(input_data.rf_channel))
|
|
286
|
+
elif prior_type == constants.TREATMENT_PRIOR_TYPE_COEFFICIENT:
|
|
287
|
+
prior_reach_scaled_counterfactual = None
|
|
288
|
+
prior_denominator = None
|
|
232
289
|
else:
|
|
233
|
-
|
|
234
|
-
model_spec.rf_roi_calibration_period, 0, reach
|
|
235
|
-
)
|
|
236
|
-
reach_counterfactual_scaled = tf.where(
|
|
237
|
-
model_spec.rf_roi_calibration_period, 0, reach_scaled
|
|
238
|
-
)
|
|
239
|
-
n_times = len(input_data.time)
|
|
240
|
-
rf_spend_counterfactual = tf.where(
|
|
241
|
-
model_spec.rf_roi_calibration_period[..., -n_times:, :],
|
|
242
|
-
0,
|
|
243
|
-
rf_spend,
|
|
244
|
-
)
|
|
290
|
+
raise ValueError(f"Unsupported prior type: {prior_type}")
|
|
245
291
|
|
|
246
292
|
return RfTensors(
|
|
247
293
|
reach=reach,
|
|
@@ -249,9 +295,8 @@ def build_rf_tensors(
|
|
|
249
295
|
rf_spend=rf_spend,
|
|
250
296
|
reach_transformer=reach_transformer,
|
|
251
297
|
reach_scaled=reach_scaled,
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
rf_spend_counterfactual=rf_spend_counterfactual,
|
|
298
|
+
prior_reach_scaled_counterfactual=prior_reach_scaled_counterfactual,
|
|
299
|
+
prior_denominator=prior_denominator,
|
|
255
300
|
)
|
|
256
301
|
|
|
257
302
|
|
|
@@ -266,18 +311,12 @@ class OrganicRfTensors:
|
|
|
266
311
|
using the model's organic RF data.
|
|
267
312
|
organic_reach_scaled: An organic reach tensor normalized by population and
|
|
268
313
|
by the median value.
|
|
269
|
-
organic_reach_counterfactual: An organic reach tensor with media
|
|
270
|
-
counterfactual values.
|
|
271
|
-
organic_reach_counterfactual_scaled: An organic reach tensor with media
|
|
272
|
-
counterfactual scaled values.
|
|
273
314
|
"""
|
|
274
315
|
|
|
275
316
|
organic_reach: tf.Tensor | None = None
|
|
276
317
|
organic_frequency: tf.Tensor | None = None
|
|
277
318
|
organic_reach_transformer: transformers.MediaTransformer | None = None
|
|
278
319
|
organic_reach_scaled: tf.Tensor | None = None
|
|
279
|
-
organic_reach_counterfactual: tf.Tensor | None = None
|
|
280
|
-
organic_reach_counterfactual_scaled: tf.Tensor | None = None
|
|
281
320
|
|
|
282
321
|
|
|
283
322
|
def build_organic_rf_tensors(
|
|
@@ -298,14 +337,10 @@ def build_organic_rf_tensors(
|
|
|
298
337
|
tf.convert_to_tensor(input_data.population, dtype=tf.float32),
|
|
299
338
|
)
|
|
300
339
|
organic_reach_scaled = organic_reach_transformer.forward(organic_reach)
|
|
301
|
-
organic_reach_counterfactual = tf.zeros_like(organic_reach)
|
|
302
|
-
organic_reach_counterfactual_scaled = tf.zeros_like(organic_reach_scaled)
|
|
303
340
|
|
|
304
341
|
return OrganicRfTensors(
|
|
305
342
|
organic_reach=organic_reach,
|
|
306
343
|
organic_frequency=organic_frequency,
|
|
307
344
|
organic_reach_transformer=organic_reach_transformer,
|
|
308
345
|
organic_reach_scaled=organic_reach_scaled,
|
|
309
|
-
organic_reach_counterfactual=organic_reach_counterfactual,
|
|
310
|
-
organic_reach_counterfactual_scaled=organic_reach_counterfactual_scaled,
|
|
311
346
|
)
|