Thanks for the quick reply! This is very helpful. Attached is what my adstock decays look like using samples = mmm.adstock.sample_curve(parameters=mmm.fit_result). All my channels follow a similar decay rate. I’m using 0.15.1 with the regular MMM api, not the multidimensional one (I’m using the end to end example notebook as a guide).
For the following statement, I’m not sure I understand. Does that mean if my weekly budget is 1000 with 4 channels, each channel gets 250, and it attempts to optimize from there?
….the optimizer distribute spend evenly across channels, if this assumption is different to your historical data (you never spend evenly every day) then results can change.
So if I have budget bounds for one channel that are 300-400, then the optimization wouldn’t work correctly? You noted that there exists a parameter that works better for my use case, what is it? Is it budget_distribution_over_period? There’s no set spend distribution in my dataset so I am inclined to follow an even distribution of the recommendations.
In the end to end example notebook spend wasn’t evenly distributed every day and the regular MMM api optimizer was used. Here is the example I am following (excluding * len(channel_columns) as that seems to be a mistake in the documentation based on an earlier post I made).
mean_spend_per_period_test = (
X_test[channel_columns].sum(axis=0).div(num_periods * len(channel_columns))
)
budget_bounds = {
key: [(1 - percentage_change) * value, (1 + percentage_change) * value]
for key, value in (mean_spend_per_period_test).to_dict().items()
}
For an input budget of 37615 per week across all my channels, the avg spend of each channel, an optimization period of len(df)=60 weeks, and noise level=0, I get a response of 0.676 per week. For an optimization period of 8 weeks I get 0.674.
Avg spends
{
"channel A": 15510,
"channel B": 7123,
"channel C": 1841,
"channel D": 4096,
"channel E": 9045,
}
Budget bounds based on 50% flexibility from avg spend were:
channel A: $7,755 - $23,266, channel B: $3,562 - $10,685, channel C: $920 - $2,761, channel D: $2,048 - $6,144, channel E: $4,522 - $13,567
allocation_strategy, optimization_result = mmm.optimize_budget(response_variable=‘total_contribution’,budget=37615,num_periods=60,budget_bounds=budget_bounds,minimize_kwargs={“method”: “SLSQP”,“options”: {“ftol”: 1e-9, “maxiter”: 5000},},)
response_optimal = mmm.sample_response_distribution(
allocation_strategy=allocation_strategy,
time_granularity="weekly",
num_periods=60,
noise_level=0,
)
channel_contribution = response_optimal["channel_contribution"].mean(dim="sample").sum(dim="date") * mmm.get_target_transformer()["scaler"].scale_
Model was fit with GeometricAdstock(l_max=4, normalize=True), saturation=LogisticSaturation()
So in essence, it’s telling me that for 8 weeks, I should reallocate spend from googleads into other channels, but for 60 weeks I should put more spend into googleads. Does this make sense given my adstock and saturation curves? Thanks for all your feedback, this is super helpful for my learning on this awesome package!