Machine Learning

Preparation of Budgets for Mixing Music Python | by Ryan O'SUllivan | Jan, 2025

Part 3 of hands to help you know the MMM in PMC

Looking at the data science
Photo by Fowfiguiguiguiguya on Nscwasch

Welcome to Section 3 of my series with Marketing Mix Modeling (Mmm), hands, guide to help you know the MMM. In every series, we will cover important topics such as model training, verification, estimating and money laundering, is all used by the powerful PMC marketing Python package. Even if you are new to MMM or look at your writing skills, this series will equip you with literal tools and understanding to improve your marketing strategies.

If you missed a section 2 checked here:

In a third cell of a series that will cover how to start the business value in our marketing mixing models by covering the following areas:

  • Why do organizations add their sales budget?
  • How can we use the results of our model mix model to perform budgets properly?
  • Python Walkthrough showing how to make a budget using PMC marketing.

The perfect brochure can be found here:

User-produced picture

This famous quotation (from John Wakerker I think?!) Shows a challenge and opportunity to market. While modern-day Analytics come long, the challenge is available: Understanding which parts of your budget to bring the amount.

Marketing stations may vary from their performance and ROI for a number of features:

  • The audience reaches and engagement – Some channels work better in reaching some hopes matched with your target audience.
  • Access Cost – The cost of accessing hopes are different between channels.
  • Channel saturation – Excessive use of market station can lead to reducing return.

This variation forms the opportunity to ask sensitive questions that can change your Marketing Strategy:

A photo that is produced by the user

The useful budget use is a critical part of modern marketing strategies. By installing the MMM results, businesses can make informed decisions about how to carry their services about the main impact. The MMM provides details on how different stations are giving in full sales, which allows us to identify opportunities and improve. In the following sections, we will examine how we can translate the MMM out of the budget plans.

2.1 In response to curves

The response curve can interpret the MMM results into a complete form, indicating how selling responds to waste each marketing channel.

User-produced picture

Only the curves only is the most powerful, allowing us to work when we are at a level. The answer is used above as an example, we can determine that a sales offer from social changes as we spend more. And we can see the seeing when the refunds of the decrease begins to work. But what if we want to try and respond more than what – if the conditions such to the introduction budget provided is a complete limited budget? This is where the direct system comes in – Let's check this in the next section!

2.2 Direct Plans

Linear system is a way of doing well can be used to find the highest solution that has been given some issues. It is a very flexible tool from operation research but not usually recognized. It is used to solve organizing, submitting and the allocation of resources allocation. We will evaluate how we can use to make budgets for sales.

Let's try and understand the exact program for the simple budget problem:

  • Variable decisions (x): These are an unknown price we want to measure high amounts of eg.
  • Objective Work (z): Linear Equation tries to minimize or grow eg. To increase the amount of sales offer at each station.
  • Issues: Other variable decisions, usually represented by direct imbalance, a marketing budget is equal to $ 50m, budget for a channel between £ 5m and £ 15m.
A photo that is produced by the user

Meeting all issues form a potential region, the set of all the possible solutions that satisfy the issues provided. The purpose of the direct plan is to determine the point within the potential region that illustrates the purpose of the purpose.

Given the Saturesaturation transformation apply to each marketing station, preparing for the Station's scale budgets is actually an illegal planning problem. Slarns of a very little scene (SLLSQP) is a algorithm used to solve non-line planning problems. It allows equality and issues of inequality that makes it a reasonable choice of our case.

  • Synchronization barriers eg complete sales budget is equal to $ 50m
  • Issues of inequality EG CHANEL LEVEL BUBLUES between £ 5m and £ 15m

SlIPH have been the best implementation of SLLsqp:

The example below shows how we can use it:

from scipy.optimize import minimize

result = minimize(
fun=objective_function, # Define your ROI function here
x0=initial_guess, # Initial guesses for spends
bounds=bounds, # Channel-level budget constraints
constraints=constraints, # Equality and inequality constraints
method='SLSQP'
)
print(result)

Writing the budget use code from the beginning is a complex but most beneficial. Fortunately, the PMC marketing The party has made a weighting lift, providing a strong framework for the budget conditions. In the following section, we will examine how their package can plan the budget allocation process and make it available to analyst.

Now we understand how to use the MMM to do the budgets well, let's look at how much the amount we can drive using our model from the last article! In this time of travel we will cover:

  • Imitation data
  • Training the model
  • To ensure the model
  • To respond to curves
  • Budget performance

3.1 imitating the data

We will reset the data that produces data from the original article. If you want a reminder to the data producing data, see the first article where we made a detailed walk:

np.random.seed(10)

# Set parameters for data generator
start_date = "2021-01-01"
periods = 52 * 3
channels = ["tv", "social", "search"]
adstock_alphas = [0.50, 0.25, 0.05]
saturation_lamdas = [1.5, 2.5, 3.5]
betas = [350, 150, 50]
spend_scalars = [10, 15, 20]

df = dg.data_generator(start_date, periods, channels, spend_scalars, adstock_alphas, saturation_lamdas, betas)

# Scale betas using maximum sales value - this is so it is comparable to the fitted beta from pymc (pymc does feature and target scaling using MaxAbsScaler from sklearn)
betas_scaled = [
((df["tv_sales"] / df["sales"].max()) / df["tv_saturated"]).mean(),
((df["social_sales"] / df["sales"].max()) / df["social_saturated"]).mean(),
((df["search_sales"] / df["sales"].max()) / df["search_saturated"]).mean()
]

# Calculate contributions
contributions = np.asarray([
round((df["tv_sales"].sum() / df["sales"].sum()), 2),
round((df["social_sales"].sum() / df["sales"].sum()), 2),
round((df["search_sales"].sum() / df["sales"].sum()), 2),
round((df["demand"].sum() / df["sales"].sum()), 2)
])

df[["date", "demand", "demand_proxy", "tv_spend_raw", "social_spend_raw", "search_spend_raw", "sales"]]

A photo that is produced by the user

3.2 Training the model

Now we will be able to train model in the first story. We will prepare for the same training data as the last time:

  • Dating the data into factors and target.
  • Creating indices of train pieces and times.

However, as the focus of this article is not limited to the model, we will include a variable of control rather than the model – this model will be well raised – it will give us good results to show how we can book.

# set date column
date_col = "date"

# set outcome column
y_col = "sales"

# set marketing variables
channel_cols = ["tv_spend_raw",
"social_spend_raw",
"search_spend_raw"]

# set control variables
control_cols = ["demand"]

# create arrays
X = df[[date_col] + channel_cols + control_cols]
y = df[y_col]

# set test (out-of-sample) length
test_len = 8

# create train and test indexs
train_idx = slice(0, len(df) - test_len)
out_of_time_idx = slice(len(df) - test_len, len(df))

mmm_default = MMM(
adstock=GeometricAdstock(l_max=8),
saturation=LogisticSaturation(),
date_column=date_col,
channel_columns=channel_cols,
control_columns=control_cols,
)

fit_kwargs = {
"tune": 1_000,
"chains": 4,
"draws": 1_000,
"target_accept": 0.9,
}

mmm_default.fit(X[train_idx], y[train_idx], **fit_kwargs)

3.3 Ensure the model

Before we get into practice, lets check our model fits well. We first look at the real donations:

channels = np.array(["tv", "social", "search", "demand"])

true_contributions = pd.DataFrame({'Channels': channels, 'Contributions': contributions})
true_contributions= true_contributions.sort_values(by='Contributions', ascending=False).reset_index(drop=True)
true_contributions = true_contributions.style.bar(subset=['Contributions'], color='lightblue')

true_contributions

A photo that is produced by the user

As expected, our model meets too close to true donations:

mmm_default.plot_waterfall_components_decomposition(figsize=(10,6));
A photo that is produced by the user

3.4 In response to curves

Before we enter the budget operation, let's look at the answer curves. There are two ways to look at the curves in PMC marketing Package:

  1. A direct curves of reply
  2. Currency Share Currency Cost

Let's start with direct response curves. In curds are directly directed curds to the only spreading structure of weekly against the weekly contribution to each station.

Below we plan specific reaction curves:

fig = mmm_default.plot_direct_contribution_curves(show_fit=True, xlim_max=1.2)
[ax.set(xlabel="spend") for ax in fig.axes];
User-produced picture

The cost of sharing the cost of the curves are not yet another way to compare stations. When Δ = 1.0, the channel spends we live at the same level as the training data. When Δ = 1.2, the use of the channel has increased by 20%.

Below we organize cost budget curves:

mmm_default.plot_channel_contributions_grid(start=0, stop=1.5, num=12, figsize=(15, 7));
User-produced picture

And we can change X-axis to show the total use amounts:

mmm_default.plot_channel_contributions_grid(start=0, stop=1.5, num=12, absolute_xrange=True, figsize=(15, 7));
a photo that is produced by the user

Rescue curves are good tools to help you think about future marketing budget at the station level. The following allows us to do them to actions and work some of the budget situations!

3.5 Budget Use

In order to start with the AST AS PRLANAMES:

  • PERC_Change: This is used to set the issues surrounding the minutes and Max Cerse per station. The incident helps to keep the situation sound and mean that we do not take the closest responding curves of the model that has seen training.
  • Budget_len: This is the length of the budget condition in the weeks.

We will start through the length of budget situation to select the most recent data time.

perc_change = 0.20
budget_len = 12
budget_idx = slice(len(df) - test_len, len(df))
recent_period = X[budget_idx][channel_cols]

recent_period

User-produced picture

We then use this latest time to set up all budget constraints and channel issues at the week level:

# set overall budget constraint (to the nearest £1k)
budget = round(recent_period.sum(axis=0).sum() / budget_len, -3)

# record the current budget split by channel
current_budget_split = round(recent_period.mean() / recent_period.mean().sum(), 2)

# set channel level constraints
lower_bounds = round(recent_period.min(axis=0) * (1 - perc_change))
upper_bounds = round(recent_period.max(axis=0) * (1 + perc_change))

budget_bounds = {
channel: [lower_bounds[channel], upper_bounds[channel]]
for channel in channel_cols
}

print(f'Overall budget constraint: {budget}')
print('Channel constraints:')
for channel, bounds in budget_bounds.items():
print(f' {channel}: Lower Bound = {bounds[0]}, Upper Bound = {bounds[1]}')

A photo that is produced by the user

Now is the time to use our situation! We feed the right details and parameters and retrieve the use. We compare it to take a complete budget and distinguish you through the current budget separation (which we have called real use).

model_granularity = "weekly"

# run scenario
allocation_strategy, optimization_result = mmm_default.optimize_budget(
budget=budget,
num_periods=budget_len,
budget_bounds=budget_bounds,
minimize_kwargs={
"method": "SLSQP",
"options": {"ftol": 1e-9, "maxiter": 5_000},
},
)

response = mmm_default.sample_response_distribution(
allocation_strategy=allocation_strategy,
time_granularity=model_granularity,
num_periods=budget_len,
noise_level=0.05,
)

# extract optimal spend
opt_spend = pd.Series(allocation_strategy, index=recent_period.mean().index).to_frame(name="opt_spend")
opt_spend["avg_spend"] = budget * current_budget_split

# plot actual vs optimal spend
fig, ax = plt.subplots(figsize=(9, 4))
opt_spend.plot(kind='barh', ax=ax, color=['blue', 'orange'])

plt.xlabel("Spend")
plt.ylabel("Channel")
plt.title("Actual vs Optimal Spend by Channel")
plt.legend(["Optimal Spend", "Actual Spend"])
plt.legend(["Optimal Spend", "Actual Spend"], loc='lower right', bbox_to_anchor=(1.5, 0.0))

plt.show()

User-produced picture

We can see the proposal submitting a budget from digital stations to the TV. But what does it contribute to the sale?

Counting the correct capital contribution we need to feed with a new amount of spending per channel and any other variables in the model. We only want, so feed with the specified amount from the latest period of this. We will also consult a financial offer for a similar waste.

# create dataframe with optimal spend
last_date = mmm_default.X["date"].max()
new_dates = pd.date_range(start=last_date, periods=1 + budget_len, freq="W-MON")[1:]
budget_scenario_opt = pd.DataFrame({"date": new_dates,})
budget_scenario_opt["tv_spend_raw"] = opt_spend["opt_spend"]["tv_spend_raw"]
budget_scenario_opt["social_spend_raw"] = opt_spend["opt_spend"]["social_spend_raw"]
budget_scenario_opt["search_spend_raw"] = opt_spend["opt_spend"]["search_spend_raw"]
budget_scenario_opt["demand"] = X[budget_idx][control_cols].mean()[0]

# calculate overall contribution
scenario_contrib_opt = mmm_default.sample_posterior_predictive(
X_pred=budget_scenario_opt, extend_idata=False
)

opt_contrib = scenario_contrib_opt.mean(dim="sample").sum()["y"].values

# create dataframe with avg spend
last_date = mmm_default.X["date"].max()
new_dates = pd.date_range(start=last_date, periods=1 + budget_len, freq="W-MON")[1:]
budget_scenario_avg = pd.DataFrame({"date": new_dates,})
budget_scenario_avg["tv_spend_raw"] = opt_spend["avg_spend"]["tv_spend_raw"]
budget_scenario_avg["social_spend_raw"] = opt_spend["avg_spend"]["social_spend_raw"]
budget_scenario_avg["search_spend_raw"] = opt_spend["avg_spend"]["search_spend_raw"]
budget_scenario_avg["demand"] = X[budget_idx][control_cols].mean()[0]

# calculate overall contribution
scenario_contrib_avg = mmm_default.sample_posterior_predictive(
X_pred=budget_scenario_avg , extend_idata=False
)

avg_contrib = scenario_contrib_avg.mean(dim="sample").sum()["y"].values

# calculate % increase in sales
print(f'% increase in sales: {round((opt_contrib / avg_contrib) - 1, 2)}')

A photo that is produced by the user

The full use gives us 6% sales increase! What impressive impressions you have given to do the entire budget!

Today we have seen how the powerful budget production is. It can help organizations with the monthly budget / quarter plan. Like always the key to making beautiful recommendations come from having a strong, fierce model.

Source link

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button