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/prior_sampler.py
CHANGED
|
@@ -68,147 +68,6 @@ class PriorDistributionSampler:
|
|
|
68
68
|
def __init__(self, meridian: "model.Meridian"):
|
|
69
69
|
self._meridian = meridian
|
|
70
70
|
|
|
71
|
-
def get_roi_prior_beta_m_value(
|
|
72
|
-
self,
|
|
73
|
-
alpha_m: tf.Tensor,
|
|
74
|
-
beta_gm_dev: tf.Tensor,
|
|
75
|
-
ec_m: tf.Tensor,
|
|
76
|
-
eta_m: tf.Tensor,
|
|
77
|
-
roi_or_mroi_m: tf.Tensor,
|
|
78
|
-
slope_m: tf.Tensor,
|
|
79
|
-
media_transformed: tf.Tensor,
|
|
80
|
-
) -> tf.Tensor:
|
|
81
|
-
"""Returns a tensor to be used in `beta_m`."""
|
|
82
|
-
mmm = self._meridian
|
|
83
|
-
|
|
84
|
-
# The `roi_or_mroi_m` parameter represents either ROI or mROI. For reach &
|
|
85
|
-
# frequency channels, marginal ROI priors are defined as "mROI by reach",
|
|
86
|
-
# which is equivalent to ROI.
|
|
87
|
-
media_spend = mmm.media_tensors.media_spend
|
|
88
|
-
media_spend_counterfactual = mmm.media_tensors.media_spend_counterfactual
|
|
89
|
-
media_counterfactual_scaled = mmm.media_tensors.media_counterfactual_scaled
|
|
90
|
-
# If we got here, then we should already have media tensors derived from
|
|
91
|
-
# non-None InputData.media data.
|
|
92
|
-
assert media_spend is not None
|
|
93
|
-
assert media_spend_counterfactual is not None
|
|
94
|
-
assert media_counterfactual_scaled is not None
|
|
95
|
-
|
|
96
|
-
# Use absolute value here because this difference will be negative for
|
|
97
|
-
# marginal ROI priors.
|
|
98
|
-
inc_revenue_m = roi_or_mroi_m * tf.reduce_sum(
|
|
99
|
-
tf.abs(media_spend - media_spend_counterfactual),
|
|
100
|
-
range(media_spend.ndim - 1),
|
|
101
|
-
)
|
|
102
|
-
|
|
103
|
-
if (
|
|
104
|
-
mmm.model_spec.roi_calibration_period is None
|
|
105
|
-
and mmm.model_spec.paid_media_prior_type
|
|
106
|
-
== constants.PAID_MEDIA_PRIOR_TYPE_ROI
|
|
107
|
-
):
|
|
108
|
-
# We can skip the adstock/hill computation step in this case.
|
|
109
|
-
media_counterfactual_transformed = tf.zeros_like(media_transformed)
|
|
110
|
-
else:
|
|
111
|
-
media_counterfactual_transformed = mmm.adstock_hill_media(
|
|
112
|
-
media=media_counterfactual_scaled,
|
|
113
|
-
alpha=alpha_m,
|
|
114
|
-
ec=ec_m,
|
|
115
|
-
slope=slope_m,
|
|
116
|
-
)
|
|
117
|
-
|
|
118
|
-
revenue_per_kpi = mmm.revenue_per_kpi
|
|
119
|
-
if mmm.input_data.revenue_per_kpi is None:
|
|
120
|
-
revenue_per_kpi = tf.ones([mmm.n_geos, mmm.n_times], dtype=tf.float32)
|
|
121
|
-
# Note: use absolute value here because this difference will be negative for
|
|
122
|
-
# marginal ROI priors.
|
|
123
|
-
media_contrib_gm = tf.einsum(
|
|
124
|
-
"...gtm,g,,gt->...gm",
|
|
125
|
-
tf.abs(media_transformed - media_counterfactual_transformed),
|
|
126
|
-
mmm.population,
|
|
127
|
-
mmm.kpi_transformer.population_scaled_stdev,
|
|
128
|
-
revenue_per_kpi,
|
|
129
|
-
)
|
|
130
|
-
|
|
131
|
-
if mmm.media_effects_dist == constants.MEDIA_EFFECTS_NORMAL:
|
|
132
|
-
media_contrib_m = tf.einsum("...gm->...m", media_contrib_gm)
|
|
133
|
-
random_effect_m = tf.einsum(
|
|
134
|
-
"...m,...gm,...gm->...m", eta_m, beta_gm_dev, media_contrib_gm
|
|
135
|
-
)
|
|
136
|
-
return (inc_revenue_m - random_effect_m) / media_contrib_m
|
|
137
|
-
else:
|
|
138
|
-
# For log_normal, beta_m and eta_m are not mean & std.
|
|
139
|
-
# The parameterization is beta_gm ~ exp(beta_m + eta_m * N(0, 1)).
|
|
140
|
-
random_effect_m = tf.einsum(
|
|
141
|
-
"...gm,...gm->...m",
|
|
142
|
-
tf.math.exp(beta_gm_dev * eta_m[..., tf.newaxis, :]),
|
|
143
|
-
media_contrib_gm,
|
|
144
|
-
)
|
|
145
|
-
return tf.math.log(inc_revenue_m) - tf.math.log(random_effect_m)
|
|
146
|
-
|
|
147
|
-
def get_roi_prior_beta_rf_value(
|
|
148
|
-
self,
|
|
149
|
-
alpha_rf: tf.Tensor,
|
|
150
|
-
beta_grf_dev: tf.Tensor,
|
|
151
|
-
ec_rf: tf.Tensor,
|
|
152
|
-
eta_rf: tf.Tensor,
|
|
153
|
-
roi_or_mroi_rf: tf.Tensor,
|
|
154
|
-
slope_rf: tf.Tensor,
|
|
155
|
-
rf_transformed: tf.Tensor,
|
|
156
|
-
) -> tf.Tensor:
|
|
157
|
-
"""Returns a tensor to be used in `beta_rf`."""
|
|
158
|
-
mmm = self._meridian
|
|
159
|
-
|
|
160
|
-
rf_spend = mmm.rf_tensors.rf_spend
|
|
161
|
-
rf_spend_counterfactual = mmm.rf_tensors.rf_spend_counterfactual
|
|
162
|
-
reach_counterfactual_scaled = mmm.rf_tensors.reach_counterfactual_scaled
|
|
163
|
-
frequency = mmm.rf_tensors.frequency
|
|
164
|
-
# If we got here, then we should already have RF media tensors derived from
|
|
165
|
-
# non-None InputData.reach data.
|
|
166
|
-
assert rf_spend is not None
|
|
167
|
-
assert rf_spend_counterfactual is not None
|
|
168
|
-
assert reach_counterfactual_scaled is not None
|
|
169
|
-
assert frequency is not None
|
|
170
|
-
|
|
171
|
-
inc_revenue_rf = roi_or_mroi_rf * tf.reduce_sum(
|
|
172
|
-
rf_spend - rf_spend_counterfactual,
|
|
173
|
-
range(rf_spend.ndim - 1),
|
|
174
|
-
)
|
|
175
|
-
if mmm.model_spec.rf_roi_calibration_period is not None:
|
|
176
|
-
rf_counterfactual_transformed = mmm.adstock_hill_rf(
|
|
177
|
-
reach=reach_counterfactual_scaled,
|
|
178
|
-
frequency=frequency,
|
|
179
|
-
alpha=alpha_rf,
|
|
180
|
-
ec=ec_rf,
|
|
181
|
-
slope=slope_rf,
|
|
182
|
-
)
|
|
183
|
-
else:
|
|
184
|
-
rf_counterfactual_transformed = tf.zeros_like(rf_transformed)
|
|
185
|
-
revenue_per_kpi = mmm.revenue_per_kpi
|
|
186
|
-
if mmm.input_data.revenue_per_kpi is None:
|
|
187
|
-
revenue_per_kpi = tf.ones([mmm.n_geos, mmm.n_times], dtype=tf.float32)
|
|
188
|
-
|
|
189
|
-
media_contrib_grf = tf.einsum(
|
|
190
|
-
"...gtm,g,,gt->...gm",
|
|
191
|
-
rf_transformed - rf_counterfactual_transformed,
|
|
192
|
-
mmm.population,
|
|
193
|
-
mmm.kpi_transformer.population_scaled_stdev,
|
|
194
|
-
revenue_per_kpi,
|
|
195
|
-
)
|
|
196
|
-
if mmm.media_effects_dist == constants.MEDIA_EFFECTS_NORMAL:
|
|
197
|
-
media_contrib_rf = tf.einsum("...gm->...m", media_contrib_grf)
|
|
198
|
-
random_effect_rf = tf.einsum(
|
|
199
|
-
"...m,...gm,...gm->...m", eta_rf, beta_grf_dev, media_contrib_grf
|
|
200
|
-
)
|
|
201
|
-
return (inc_revenue_rf - random_effect_rf) / media_contrib_rf
|
|
202
|
-
else:
|
|
203
|
-
# For log_normal, beta_rf and eta_rf are not mean & std.
|
|
204
|
-
# The parameterization is beta_grf ~ exp(beta_rf + eta_rf * N(0, 1)).
|
|
205
|
-
random_effect_rf = tf.einsum(
|
|
206
|
-
"...gm,...gm->...m",
|
|
207
|
-
tf.math.exp(beta_grf_dev * eta_rf[..., tf.newaxis, :]),
|
|
208
|
-
media_contrib_grf,
|
|
209
|
-
)
|
|
210
|
-
return tf.math.log(inc_revenue_rf) - tf.math.log(random_effect_rf)
|
|
211
|
-
|
|
212
71
|
def _sample_media_priors(
|
|
213
72
|
self,
|
|
214
73
|
n_draws: int,
|
|
@@ -243,40 +102,49 @@ class PriorDistributionSampler:
|
|
|
243
102
|
[mmm.n_geos, mmm.n_media_channels],
|
|
244
103
|
name=constants.BETA_GM_DEV,
|
|
245
104
|
).sample(**sample_kwargs)
|
|
246
|
-
media_transformed = mmm.adstock_hill_media(
|
|
247
|
-
media=mmm.media_tensors.media_scaled,
|
|
248
|
-
alpha=media_vars[constants.ALPHA_M],
|
|
249
|
-
ec=media_vars[constants.EC_M],
|
|
250
|
-
slope=media_vars[constants.SLOPE_M],
|
|
251
|
-
)
|
|
252
105
|
|
|
253
|
-
prior_type = mmm.model_spec.
|
|
254
|
-
if prior_type == constants.
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
106
|
+
prior_type = mmm.model_spec.effective_media_prior_type
|
|
107
|
+
if prior_type == constants.TREATMENT_PRIOR_TYPE_COEFFICIENT:
|
|
108
|
+
media_vars[constants.BETA_M] = prior.beta_m.sample(**sample_kwargs)
|
|
109
|
+
else:
|
|
110
|
+
if prior_type == constants.TREATMENT_PRIOR_TYPE_ROI:
|
|
111
|
+
treatment_parameter_m = prior.roi_m.sample(**sample_kwargs)
|
|
112
|
+
media_vars[constants.ROI_M] = treatment_parameter_m
|
|
113
|
+
elif prior_type == constants.TREATMENT_PRIOR_TYPE_MROI:
|
|
114
|
+
treatment_parameter_m = prior.mroi_m.sample(**sample_kwargs)
|
|
115
|
+
media_vars[constants.MROI_M] = treatment_parameter_m
|
|
116
|
+
elif prior_type == constants.TREATMENT_PRIOR_TYPE_CONTRIBUTION:
|
|
117
|
+
treatment_parameter_m = prior.contribution_m.sample(**sample_kwargs)
|
|
118
|
+
media_vars[constants.CONTRIBUTION_M] = treatment_parameter_m
|
|
119
|
+
else:
|
|
120
|
+
raise ValueError(f"Unsupported prior type: {prior_type}")
|
|
121
|
+
incremental_outcome_m = (
|
|
122
|
+
treatment_parameter_m * mmm.media_tensors.prior_denominator
|
|
261
123
|
)
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
124
|
+
media_transformed = mmm.adstock_hill_media(
|
|
125
|
+
media=mmm.media_tensors.media_scaled,
|
|
126
|
+
alpha=media_vars[constants.ALPHA_M],
|
|
127
|
+
ec=media_vars[constants.EC_M],
|
|
128
|
+
slope=media_vars[constants.SLOPE_M],
|
|
129
|
+
)
|
|
130
|
+
linear_predictor_counterfactual_difference = (
|
|
131
|
+
mmm.linear_predictor_counterfactual_difference_media(
|
|
132
|
+
media_transformed=media_transformed,
|
|
133
|
+
alpha_m=media_vars[constants.ALPHA_M],
|
|
134
|
+
ec_m=media_vars[constants.EC_M],
|
|
135
|
+
slope_m=media_vars[constants.SLOPE_M],
|
|
136
|
+
)
|
|
137
|
+
)
|
|
138
|
+
beta_m_value = mmm.calculate_beta_x(
|
|
139
|
+
is_non_media=False,
|
|
140
|
+
incremental_outcome_x=incremental_outcome_m,
|
|
141
|
+
linear_predictor_counterfactual_difference=linear_predictor_counterfactual_difference,
|
|
142
|
+
eta_x=media_vars[constants.ETA_M],
|
|
143
|
+
beta_gx_dev=beta_gm_dev,
|
|
273
144
|
)
|
|
274
|
-
media_vars[constants.MROI_M] = mroi_m
|
|
275
145
|
media_vars[constants.BETA_M] = tfp.distributions.Deterministic(
|
|
276
146
|
beta_m_value, name=constants.BETA_M
|
|
277
147
|
).sample()
|
|
278
|
-
else:
|
|
279
|
-
media_vars[constants.BETA_M] = prior.beta_m.sample(**sample_kwargs)
|
|
280
148
|
|
|
281
149
|
beta_eta_combined = (
|
|
282
150
|
media_vars[constants.BETA_M][..., tf.newaxis, :]
|
|
@@ -326,43 +194,51 @@ class PriorDistributionSampler:
|
|
|
326
194
|
[mmm.n_geos, mmm.n_rf_channels],
|
|
327
195
|
name=constants.BETA_GRF_DEV,
|
|
328
196
|
).sample(**sample_kwargs)
|
|
329
|
-
rf_transformed = mmm.adstock_hill_rf(
|
|
330
|
-
reach=mmm.rf_tensors.reach_scaled,
|
|
331
|
-
frequency=mmm.rf_tensors.frequency,
|
|
332
|
-
alpha=rf_vars[constants.ALPHA_RF],
|
|
333
|
-
ec=rf_vars[constants.EC_RF],
|
|
334
|
-
slope=rf_vars[constants.SLOPE_RF],
|
|
335
|
-
)
|
|
336
197
|
|
|
337
|
-
prior_type = mmm.model_spec.
|
|
338
|
-
if prior_type == constants.
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
198
|
+
prior_type = mmm.model_spec.effective_rf_prior_type
|
|
199
|
+
if prior_type == constants.TREATMENT_PRIOR_TYPE_COEFFICIENT:
|
|
200
|
+
rf_vars[constants.BETA_RF] = prior.beta_rf.sample(**sample_kwargs)
|
|
201
|
+
else:
|
|
202
|
+
if prior_type == constants.TREATMENT_PRIOR_TYPE_ROI:
|
|
203
|
+
treatment_parameter_rf = prior.roi_rf.sample(**sample_kwargs)
|
|
204
|
+
rf_vars[constants.ROI_RF] = treatment_parameter_rf
|
|
205
|
+
elif prior_type == constants.TREATMENT_PRIOR_TYPE_MROI:
|
|
206
|
+
treatment_parameter_rf = prior.mroi_rf.sample(**sample_kwargs)
|
|
207
|
+
rf_vars[constants.MROI_RF] = treatment_parameter_rf
|
|
208
|
+
elif prior_type == constants.TREATMENT_PRIOR_TYPE_CONTRIBUTION:
|
|
209
|
+
treatment_parameter_rf = prior.contribution_rf.sample(**sample_kwargs)
|
|
210
|
+
rf_vars[constants.CONTRIBUTION_RF] = treatment_parameter_rf
|
|
211
|
+
else:
|
|
212
|
+
raise ValueError(f"Unsupported prior type: {prior_type}")
|
|
213
|
+
incremental_outcome_rf = (
|
|
214
|
+
treatment_parameter_rf * mmm.rf_tensors.prior_denominator
|
|
345
215
|
)
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
216
|
+
rf_transformed = mmm.adstock_hill_rf(
|
|
217
|
+
reach=mmm.rf_tensors.reach_scaled,
|
|
218
|
+
frequency=mmm.rf_tensors.frequency,
|
|
219
|
+
alpha=rf_vars[constants.ALPHA_RF],
|
|
220
|
+
ec=rf_vars[constants.EC_RF],
|
|
221
|
+
slope=rf_vars[constants.SLOPE_RF],
|
|
222
|
+
)
|
|
223
|
+
linear_predictor_counterfactual_difference = (
|
|
224
|
+
mmm.linear_predictor_counterfactual_difference_rf(
|
|
225
|
+
rf_transformed=rf_transformed,
|
|
226
|
+
alpha_rf=rf_vars[constants.ALPHA_RF],
|
|
227
|
+
ec_rf=rf_vars[constants.EC_RF],
|
|
228
|
+
slope_rf=rf_vars[constants.SLOPE_RF],
|
|
229
|
+
)
|
|
230
|
+
)
|
|
231
|
+
beta_rf_value = mmm.calculate_beta_x(
|
|
232
|
+
is_non_media=False,
|
|
233
|
+
incremental_outcome_x=incremental_outcome_rf,
|
|
234
|
+
linear_predictor_counterfactual_difference=linear_predictor_counterfactual_difference,
|
|
235
|
+
eta_x=rf_vars[constants.ETA_RF],
|
|
236
|
+
beta_gx_dev=beta_grf_dev,
|
|
358
237
|
)
|
|
359
|
-
rf_vars[constants.MROI_RF] = mroi_rf
|
|
360
238
|
rf_vars[constants.BETA_RF] = tfp.distributions.Deterministic(
|
|
361
239
|
beta_rf_value,
|
|
362
240
|
name=constants.BETA_RF,
|
|
363
241
|
).sample()
|
|
364
|
-
else:
|
|
365
|
-
rf_vars[constants.BETA_RF] = prior.beta_rf.sample(**sample_kwargs)
|
|
366
242
|
|
|
367
243
|
beta_eta_combined = (
|
|
368
244
|
rf_vars[constants.BETA_RF][..., tf.newaxis, :]
|
|
@@ -414,9 +290,37 @@ class PriorDistributionSampler:
|
|
|
414
290
|
name=constants.BETA_GOM_DEV,
|
|
415
291
|
).sample(**sample_kwargs)
|
|
416
292
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
293
|
+
prior_type = mmm.model_spec.organic_media_prior_type
|
|
294
|
+
if prior_type == constants.TREATMENT_PRIOR_TYPE_COEFFICIENT:
|
|
295
|
+
organic_media_vars[constants.BETA_OM] = prior.beta_om.sample(
|
|
296
|
+
**sample_kwargs
|
|
297
|
+
)
|
|
298
|
+
elif prior_type == constants.TREATMENT_PRIOR_TYPE_CONTRIBUTION:
|
|
299
|
+
organic_media_vars[constants.CONTRIBUTION_OM] = (
|
|
300
|
+
prior.contribution_om.sample(**sample_kwargs)
|
|
301
|
+
)
|
|
302
|
+
incremental_outcome_om = (
|
|
303
|
+
organic_media_vars[constants.CONTRIBUTION_OM] * mmm.total_outcome
|
|
304
|
+
)
|
|
305
|
+
organic_media_transformed = mmm.adstock_hill_media(
|
|
306
|
+
media=mmm.organic_media_tensors.organic_media_scaled,
|
|
307
|
+
alpha=organic_media_vars[constants.ALPHA_OM],
|
|
308
|
+
ec=organic_media_vars[constants.EC_OM],
|
|
309
|
+
slope=organic_media_vars[constants.SLOPE_OM],
|
|
310
|
+
)
|
|
311
|
+
beta_om_value = mmm.calculate_beta_x(
|
|
312
|
+
is_non_media=False,
|
|
313
|
+
incremental_outcome_x=incremental_outcome_om,
|
|
314
|
+
linear_predictor_counterfactual_difference=organic_media_transformed,
|
|
315
|
+
eta_x=organic_media_vars[constants.ETA_OM],
|
|
316
|
+
beta_gx_dev=beta_gom_dev,
|
|
317
|
+
)
|
|
318
|
+
organic_media_vars[constants.BETA_OM] = tfp.distributions.Deterministic(
|
|
319
|
+
beta_om_value,
|
|
320
|
+
name=constants.BETA_OM,
|
|
321
|
+
).sample()
|
|
322
|
+
else:
|
|
323
|
+
raise ValueError(f"Unsupported prior type: {prior_type}")
|
|
420
324
|
|
|
421
325
|
beta_eta_combined = (
|
|
422
326
|
organic_media_vars[constants.BETA_OM][..., tf.newaxis, :]
|
|
@@ -469,7 +373,38 @@ class PriorDistributionSampler:
|
|
|
469
373
|
name=constants.BETA_GORF_DEV,
|
|
470
374
|
).sample(**sample_kwargs)
|
|
471
375
|
|
|
472
|
-
|
|
376
|
+
prior_type = mmm.model_spec.organic_media_prior_type
|
|
377
|
+
if prior_type == constants.TREATMENT_PRIOR_TYPE_COEFFICIENT:
|
|
378
|
+
organic_rf_vars[constants.BETA_ORF] = prior.beta_orf.sample(
|
|
379
|
+
**sample_kwargs
|
|
380
|
+
)
|
|
381
|
+
elif prior_type == constants.TREATMENT_PRIOR_TYPE_CONTRIBUTION:
|
|
382
|
+
organic_rf_vars[constants.CONTRIBUTION_ORF] = (
|
|
383
|
+
prior.contribution_orf.sample(**sample_kwargs)
|
|
384
|
+
)
|
|
385
|
+
incremental_outcome_orf = (
|
|
386
|
+
organic_rf_vars[constants.CONTRIBUTION_ORF] * mmm.total_outcome
|
|
387
|
+
)
|
|
388
|
+
organic_rf_transformed = mmm.adstock_hill_rf(
|
|
389
|
+
reach=mmm.organic_rf_tensors.organic_reach_scaled,
|
|
390
|
+
frequency=mmm.organic_rf_tensors.organic_frequency,
|
|
391
|
+
alpha=organic_rf_vars[constants.ALPHA_ORF],
|
|
392
|
+
ec=organic_rf_vars[constants.EC_ORF],
|
|
393
|
+
slope=organic_rf_vars[constants.SLOPE_ORF],
|
|
394
|
+
)
|
|
395
|
+
beta_orf_value = mmm.calculate_beta_x(
|
|
396
|
+
is_non_media=False,
|
|
397
|
+
incremental_outcome_x=incremental_outcome_orf,
|
|
398
|
+
linear_predictor_counterfactual_difference=organic_rf_transformed,
|
|
399
|
+
eta_x=organic_rf_vars[constants.ETA_ORF],
|
|
400
|
+
beta_gx_dev=beta_gorf_dev,
|
|
401
|
+
)
|
|
402
|
+
organic_rf_vars[constants.BETA_ORF] = tfp.distributions.Deterministic(
|
|
403
|
+
beta_orf_value,
|
|
404
|
+
name=constants.BETA_ORF,
|
|
405
|
+
).sample()
|
|
406
|
+
else:
|
|
407
|
+
raise ValueError(f"Unsupported prior type: {prior_type}")
|
|
473
408
|
|
|
474
409
|
beta_eta_combined = (
|
|
475
410
|
organic_rf_vars[constants.BETA_ORF][..., tf.newaxis, :]
|
|
@@ -511,7 +446,6 @@ class PriorDistributionSampler:
|
|
|
511
446
|
sample_shape = [1, n_draws]
|
|
512
447
|
sample_kwargs = {constants.SAMPLE_SHAPE: sample_shape, constants.SEED: seed}
|
|
513
448
|
non_media_treatments_vars = {
|
|
514
|
-
constants.GAMMA_N: prior.gamma_n.sample(**sample_kwargs),
|
|
515
449
|
constants.XI_N: prior.xi_n.sample(**sample_kwargs),
|
|
516
450
|
}
|
|
517
451
|
gamma_gn_dev = tfp.distributions.Sample(
|
|
@@ -519,6 +453,40 @@ class PriorDistributionSampler:
|
|
|
519
453
|
[mmm.n_geos, mmm.n_non_media_channels],
|
|
520
454
|
name=constants.GAMMA_GN_DEV,
|
|
521
455
|
).sample(**sample_kwargs)
|
|
456
|
+
prior_type = mmm.model_spec.non_media_treatments_prior_type
|
|
457
|
+
if prior_type == constants.TREATMENT_PRIOR_TYPE_COEFFICIENT:
|
|
458
|
+
non_media_treatments_vars[constants.GAMMA_N] = prior.gamma_n.sample(
|
|
459
|
+
**sample_kwargs
|
|
460
|
+
)
|
|
461
|
+
elif prior_type == constants.TREATMENT_PRIOR_TYPE_CONTRIBUTION:
|
|
462
|
+
non_media_treatments_vars[constants.CONTRIBUTION_N] = (
|
|
463
|
+
prior.contribution_n.sample(**sample_kwargs)
|
|
464
|
+
)
|
|
465
|
+
incremental_outcome_n = (
|
|
466
|
+
non_media_treatments_vars[constants.CONTRIBUTION_N]
|
|
467
|
+
* mmm.total_outcome
|
|
468
|
+
)
|
|
469
|
+
baseline_scaled = mmm.non_media_transformer.forward( # pytype: disable=attribute-error
|
|
470
|
+
mmm.compute_non_media_treatments_baseline()
|
|
471
|
+
)
|
|
472
|
+
linear_predictor_counterfactual_difference = (
|
|
473
|
+
mmm.non_media_treatments_normalized
|
|
474
|
+
- baseline_scaled
|
|
475
|
+
)
|
|
476
|
+
gamma_n_value = mmm.calculate_beta_x(
|
|
477
|
+
is_non_media=True,
|
|
478
|
+
incremental_outcome_x=incremental_outcome_n,
|
|
479
|
+
linear_predictor_counterfactual_difference=linear_predictor_counterfactual_difference,
|
|
480
|
+
eta_x=non_media_treatments_vars[constants.XI_N],
|
|
481
|
+
beta_gx_dev=gamma_gn_dev,
|
|
482
|
+
)
|
|
483
|
+
non_media_treatments_vars[constants.GAMMA_N] = (
|
|
484
|
+
tfp.distributions.Deterministic(
|
|
485
|
+
gamma_n_value, name=constants.GAMMA_N
|
|
486
|
+
).sample()
|
|
487
|
+
)
|
|
488
|
+
else:
|
|
489
|
+
raise ValueError(f"Unsupported prior type: {prior_type}")
|
|
522
490
|
non_media_treatments_vars[constants.GAMMA_GN] = (
|
|
523
491
|
tfp.distributions.Deterministic(
|
|
524
492
|
non_media_treatments_vars[constants.GAMMA_N][..., tf.newaxis, :]
|
|
@@ -552,10 +520,12 @@ class PriorDistributionSampler:
|
|
|
552
520
|
constants.GAMMA_C: prior.gamma_c.sample(**sample_kwargs),
|
|
553
521
|
constants.XI_C: prior.xi_c.sample(**sample_kwargs),
|
|
554
522
|
constants.SIGMA: prior.sigma.sample(**sample_kwargs),
|
|
555
|
-
constants.TAU_G:
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
523
|
+
constants.TAU_G: (
|
|
524
|
+
_get_tau_g(
|
|
525
|
+
tau_g_excl_baseline=tau_g_excl_baseline,
|
|
526
|
+
baseline_geo_idx=mmm.baseline_geo_idx,
|
|
527
|
+
).sample()
|
|
528
|
+
),
|
|
559
529
|
}
|
|
560
530
|
base_vars[constants.MU_T] = tfp.distributions.Deterministic(
|
|
561
531
|
tf.einsum(
|
|
@@ -599,7 +569,7 @@ class PriorDistributionSampler:
|
|
|
599
569
|
)
|
|
600
570
|
non_media_treatments_vars = (
|
|
601
571
|
self._sample_non_media_treatments_priors(n_draws, seed)
|
|
602
|
-
if mmm.
|
|
572
|
+
if mmm.non_media_treatments_normalized is not None
|
|
603
573
|
else {}
|
|
604
574
|
)
|
|
605
575
|
|