Return of Investments for online marketing

Try me

Open In ColabBinder

The following metrics and indicators determine the expenditures and return of investments of marketing investments in paid inclusion (including your company’s web page in search results) for your company:

  • S (Total Search results in period): Total number of times the keywords are used in searches in the planning period.

  • CPM (Cost per 1000 impressions): Cost of the search engine per every 1000 impressions, every time your website appears in a search result

  • CPC (Cost per click): Cost per every click

  • CTR (Click-Through Rate): rate between the number of clicks and number of impressions

  • CVR (Conversion Rate): rate between the number of visitors and the number of users

With this, the number of visitors (V) and the number of users (U) can be calculated as:

\(U = V * CVR = S * CTR * CVR\)

The total costs (\(C_t\)) of the search engine investments are:

\(C_t = CPC*V + CPM/1000*S\)

The ARPU (Average revenue per user in planning period) is the average revenue per user, or the total revenue in the planning period (R), divided by the number of users:

\(ARPU = R/U\)

The Return of Investments for online marketing is calculated as:

\(ROI = \frac{R - C_t}{C_t}\)

After some research, you have found that the different metrics can be modeled as normal distributions with the following parameters:

Metric

Mean

Standard Deviation

Search results

600000

100000

CTR

0.05

0.01

CVR

0.5

0.1

These are the search engine fees for your keywords:

  • CPM = 0,3€

  • CPC = 0,75€

You estimate your ARPU in 5€

a. Calculate the total costs, the total Return of Investments and the average cost per acquisition using Montecarlo Simulation

Ok, Let’s first import the libraries we will need:

[1]:
import pandas as pd
import numpy as np

Ok, now we can start with the simulation. First, we will define the number of simulations we want to run. We will use 100000 simulations, but you can change this number to see how the results change. Once, we define the number of simulations, we will also define the properties of the random variables we want to simulate with Montecarlo (mean and standard deviation). We will use the numpy library to generate the random variables. Finally, in this basic implementation, we will define a for loop to run the simulation and store the results in a dataframe. We will also calculate the ROI for each simulation and store it in the dataframe. Finally, We will use the describe function to get the statistics of the results.

[ ]:
# Number of simulations
num_simulations = 100000

# Parameters of the revenue model
#Data Search Results and search engines costs
#Data Search Results and search engines costs
search_results_avg = 600000
search_results_std = 100000

ctr_mean = 0.05
ctr_std = 0.01

cvr_mean = 0.5
cvr_std = 0.1

# Costs and unitary profit
CPM = 0.3
CPC = 0.75

ARPU = 5

# We initialize a numpy array with the number of simulations and the number of variables we want to simulate
results = np.zeros((num_simulations, 8))

# We run the simulation
for i in range(num_simulations):
    # First we calculate the total number of impacts or searches
    total_impacts = np.random.normal(search_results_avg,search_results_std)

    # Then we calculate the total number of visitors using the Click-Through Rate (CTR)
    CTR = np.random.normal(ctr_mean, ctr_std)
    total_visitors = total_impacts * CTR

    # Then we calculate the total number of customers using the Conversion Rate (CVR)
    CVR = np.random.normal(cvr_mean, cvr_std)
    total_customers = total_visitors * CVR

    # Finally, we calculate the total cost and the total revenues, using the costs and the ARPU
    total_cost = CPC*total_visitors + CPM*total_impacts/1000
    total_revenues = total_customers * ARPU
    ROI = (total_revenues - total_cost)/total_cost

    # We store the results in the numpy array, in row i
    results[i,:] = [total_impacts, CTR, total_visitors, CVR, total_customers, total_cost, total_revenues, ROI]

# We create a dataframe with the results
df_results = pd.DataFrame(results, columns = ['Total impacts', 'CTR', 'Total visitors', 'CVR', 'Total customers', 'Total cost', 'Total revenues', 'ROI'])
results.describe()

This code works and is easy to interpret, but it does not leverage one of the most outstanding features of Numpy, working with vectors and matrices. Let’s see how we can improve the code using vectors and matrices, avoiding the for loop:

[2]:
num_simulations = 100000

#Data Search Results and search engines costs
search_results_avg = 600000
search_results_std = 100000

ctr_mean = 0.05
ctr_std = 0.01

cvr_mean = 0.5
cvr_std = 0.1

# Costs and unitary profit
CPM = 0.3
CPC = 0.75

ARPU = 5


# Total number of impacts or searches, each row represents a simulation
total_impacts = np.random.normal(search_results_avg,search_results_std, num_simulations)

# Click-Through Rate, each row represents a simulation
CTR = np.random.normal(ctr_mean, ctr_std, num_simulations)

# Total clicks or visitors
total_visitors = total_impacts * CTR

# Conversion rate
CVR = np.random.normal(cvr_mean, cvr_std, num_simulations)

#Total customers or users
total_customers = total_visitors * CVR

#Total search engine costs
total_cost = CPC*total_visitors + CPM*total_impacts/1000

#Total revenues estimated from ARPU
total_revenues = total_customers * ARPU

#ROI (total revenues - total costs)/total cost

ROI = (total_revenues - total_cost)/total_cost


results_df = pd.DataFrame({'impacts':total_impacts, 'CTR':CTR, 'Visitors':total_visitors, 'CVR':CVR, 'Customers':total_customers, 'Revenues':total_revenues, 'Cost':total_cost, 'ROI':ROI})

#Now we can see the statistics using the describe function:
results_df.describe()

[2]:
impacts CTR Visitors CVR Customers Revenues Cost ROI
count 1.000000e+05 100000.000000 100000.000000 100000.000000 100000.000000 100000.000000 100000.000000 100000.000000
mean 5.999030e+05 0.050052 30031.266831 0.499396 14997.328542 74986.642710 22703.421018 2.301716
std 1.001245e+05 0.010003 7901.093998 0.099647 5015.323090 25076.615449 5945.011469 0.658838
min 1.627489e+05 0.006749 3111.804727 0.095343 1425.791553 7128.957767 2472.171271 -0.369106
25% 5.327494e+05 0.043324 24461.139430 0.432389 11421.034780 57105.173899 18513.188951 1.858309
50% 5.997867e+05 0.050051 29532.234129 0.499373 14445.367567 72226.837833 22325.493179 2.301226
75% 6.674925e+05 0.056801 35082.456403 0.566536 18009.074903 90045.374513 26502.929706 2.745805
max 1.045158e+06 0.092695 73104.943275 0.958135 47847.191767 239235.958836 55099.856282 5.337203

Note that the only difference is that now we have used the numpy library to generate bi-dimensional matrices with the random variables, and then just algebraic operations to calculate and store the results. This is much more efficient than using a for loop.

Ok, now we can answer the questions just use the function hist() of the dataframe to plot the histogram:

[3]:
#Check if our distribution is normally distributed

hist = results_df.hist(bins=100)
../../_images/Simulation_Solved_Return_of_search_engine_investments_9_0.png

Now, to calculate the confidence interval of the ROI, we can use the standard distribution, as we have a large number of simulations. We can use the scipy library to get the confidence interval, using the function norm.ppf() to get the quantiles of the standard distribution. We can also use the describe function to get the statistics of the results:

[4]:
import scipy.stats as st
[5]:
# Get the confidence interval of the ROI using the standard distribution
interval = (st.norm.ppf(0.025, loc= np.mean(ROI), scale=np.std(ROI)), st.norm.ppf(0.975, loc= np.mean(ROI), scale=np.std(ROI)))
print(interval)
(1.010423544564778, 3.593008469189609)

The 95% confidence interval of the ROI will be between these 2 values

Note that the function norm.ppf takes the quantile as the first argument, and the mean and standard deviation as the second and third arguments. Since we want to get the 95% confidence interval, we use 0.025 and 0.975 as the quantiles. To get the average and standard distribution of the ROI, we use the numpy functions mean and std, which will return the empirical mean and standard deviation of the data generated during the simulation.

[6]:
# We can also get the empirical 95% confidence interval of all metrics using describe
results_df.describe(percentiles=[0.025, 0.975])
[6]:
impacts CTR Visitors CVR Customers Revenues Cost ROI
count 1.000000e+05 100000.000000 100000.000000 100000.000000 100000.000000 100000.000000 100000.000000 100000.000000
mean 5.999030e+05 0.050052 30031.266831 0.499396 14997.328542 74986.642710 22703.421018 2.301716
std 1.001245e+05 0.010003 7901.093998 0.099647 5015.323090 25076.615449 5945.011469 0.658838
min 1.627489e+05 0.006749 3111.804727 0.095343 1425.791553 7128.957767 2472.171271 -0.369106
2.5% 4.026289e+05 0.030309 15950.632852 0.304002 6727.525477 33637.627384 12107.334547 1.010177
50% 5.997867e+05 0.050051 29532.234129 0.499373 14445.367567 72226.837833 22325.493179 2.301226
97.5% 7.955853e+05 0.069589 46908.820897 0.693940 26258.565698 131292.828488 35404.215418 3.587235
max 1.045158e+06 0.092695 73104.943275 0.958135 47847.191767 239235.958836 55099.856282 5.337203