Spaces:
Sleeping
Sleeping
Commit
·
7d3e93d
1
Parent(s):
4062d22
fixed code to get marginal cpc curve to start from origin and moved graphs to show cpc even when breakeven is not reached
Browse files- marginal_cpc_calculator.py +40 -28
marginal_cpc_calculator.py
CHANGED
@@ -6,8 +6,10 @@ import pandas as pd
|
|
6 |
def hello():
|
7 |
print ("world!")
|
8 |
|
9 |
-
def polynomial_func(x, a,b,c,d):
|
10 |
-
|
|
|
|
|
11 |
return y
|
12 |
|
13 |
def get_country_metrics(country,min_date='2023-07-01',max_date='2023-09-01'):
|
@@ -73,14 +75,18 @@ def calculate_max_spend(df,min_date,max_date,
|
|
73 |
|
74 |
try:
|
75 |
output_msg=[]
|
76 |
-
plt.style.use('
|
77 |
fig = plt.figure(figsize=(18,6))
|
78 |
|
79 |
-
params, cv = curve_fit(polynomial_func, df_temp['cum_cost'],df_temp['marginal_income'].fillna(0), p0=(1, 1,1,1))
|
80 |
-
a,b,c,d = params
|
|
|
|
|
|
|
81 |
|
82 |
# determine quality of the fit
|
83 |
-
squaredDiffs = np.square(df_temp['marginal_income'].fillna(0) - polynomial_func(df_temp['cum_cost'], a,b,c,d))
|
|
|
84 |
squaredDiffsFromMean = np.square(df_temp['marginal_income'].fillna(0) - np.mean(df_temp['marginal_income'].fillna(0)))
|
85 |
rSquared = 1 - np.sum(squaredDiffs) / np.sum(squaredDiffsFromMean)
|
86 |
|
@@ -90,12 +96,16 @@ def calculate_max_spend(df,min_date,max_date,
|
|
90 |
|
91 |
# inspect the parameters
|
92 |
if pprint==True:
|
93 |
-
output_msg.append(f"Marginal income equation Y = {a} * x - {b} * x^2 + {c} * x^3 + {d}")
|
|
|
94 |
|
95 |
# calculate max costs when it becomes negative ROAS
|
|
|
|
|
|
|
96 |
df_marginal = pd.DataFrame(zip(np.arange(500000),
|
97 |
-
polynomial_func(np.arange(500000), a,b,c
|
98 |
-
)).rename(columns={0:'cumulative_cost',1:'marginal_income'})
|
99 |
# join actuals to get the full picture
|
100 |
_ = df_temp[['cost','cpc','cum_cost', 'cum_clicks', 'cum_cpc', 'cum_revenue', 'cum_income']]
|
101 |
# converting cost to integer in order to join with the marginal dataset
|
@@ -136,32 +146,34 @@ def calculate_max_spend(df,min_date,max_date,
|
|
136 |
output_msg.append(f"For this spend, marginal_cpc={marginal_cpc_HAS}, cumulative_clicks={cum_clicks_HAS}, Average_cpc={cum_cpc_HAS}, cumulative_revenue={cum_revenue_HAS}")
|
137 |
output_msg.append(f"Total amount spent in negative ROAS={total_negative_roas_spend}")
|
138 |
# print (output_msg)
|
139 |
-
try:
|
140 |
-
ax1 = fig.add_subplot(121);
|
141 |
-
plt.scatter(df_temp['cum_cost'],df_temp['cpc']);
|
142 |
-
plt.axhline(1*cvr*aov,color='black',linestyle='--');plt.axhline(1*cvr*aov*pc,color='blue',linestyle='--');
|
143 |
-
plt.annotate(f'Any clicks above {np.round(cvr*aov,2)} SEK cpc has negative ROAS \n Above {np.round(cvr*aov*pc,2)} SEK is negative PC',size=12,xy=[0,40], color="black")
|
144 |
-
plt.xlabel('cumulative cost'); plt.ylabel('cpc')
|
145 |
-
# ax2.axes.get_xaxis().set_visible(False)
|
146 |
-
ax1.title.set_text('CPC for at different spend levels');
|
147 |
-
except:
|
148 |
-
pass
|
149 |
-
try:
|
150 |
-
ax2 = fig.add_subplot(122)
|
151 |
-
plt.plot(df_temp['cum_cost'],df_temp['marginal_income'], '.', label="data")
|
152 |
-
plt.plot(df_temp['cum_cost'], polynomial_func(df_temp['cum_cost'], a,b,c,d), '--', color='blue', label="fitted")
|
153 |
-
plt.xlabel('cumulative cost'); plt.ylabel('marginal income')
|
154 |
-
ax2.title.set_text('Net income at different spend levels')
|
155 |
-
except:
|
156 |
-
pass
|
157 |
else:
|
158 |
marginal_cpc,cum_clicks,cum_cpc,cum_revenue = np.nan, np.nan, np.nan, np.nan
|
159 |
total_negative_roas_spend=np.nan
|
160 |
if pprint==True:
|
|
|
161 |
print (f"Not enough data for mCPC analysis. Max threshold resulted in {max_spend_threshold}. Highest amount spent during this period is: {highest_amount_spent}")
|
162 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
163 |
values = (max_spend_threshold,highest_amount_spent,total_negative_roas_spend,marginal_cpc,cum_clicks,cum_cpc,cum_revenue,rSquared)
|
164 |
return fig,output_msg,values
|
|
|
165 |
|
166 |
def loop_mCPC_countries(df,min_date,max_date,
|
167 |
country_list=['UK', 'DE', 'US', 'NL', 'SE', 'CH', 'BE', 'EU', 'FR', 'AU'],
|
|
|
6 |
def hello():
|
7 |
print ("world!")
|
8 |
|
9 |
+
# def polynomial_func(x, a,b,c,d):
|
10 |
+
# y = a * x - b * x**2 + c * x**3 + d
|
11 |
+
def polynomial_func(x, a,b,c):
|
12 |
+
y = a * x - b * x**2 + c * x**3
|
13 |
return y
|
14 |
|
15 |
def get_country_metrics(country,min_date='2023-07-01',max_date='2023-09-01'):
|
|
|
75 |
|
76 |
try:
|
77 |
output_msg=[]
|
78 |
+
plt.style.use('fivethirtyeight')
|
79 |
fig = plt.figure(figsize=(18,6))
|
80 |
|
81 |
+
# params, cv = curve_fit(polynomial_func, df_temp['cum_cost'],df_temp['marginal_income'].fillna(0), p0=(1, 1,1,1))
|
82 |
+
# a,b,c,d = params
|
83 |
+
params, cv = curve_fit(polynomial_func, df_temp['cum_cost'],df_temp['marginal_income'].fillna(0), p0=(1, 1,1))
|
84 |
+
a,b,c = params
|
85 |
+
|
86 |
|
87 |
# determine quality of the fit
|
88 |
+
# squaredDiffs = np.square(df_temp['marginal_income'].fillna(0) - polynomial_func(df_temp['cum_cost'], a,b,c,d))
|
89 |
+
squaredDiffs = np.square(df_temp['marginal_income'].fillna(0) - polynomial_func(df_temp['cum_cost'], a,b,c))
|
90 |
squaredDiffsFromMean = np.square(df_temp['marginal_income'].fillna(0) - np.mean(df_temp['marginal_income'].fillna(0)))
|
91 |
rSquared = 1 - np.sum(squaredDiffs) / np.sum(squaredDiffsFromMean)
|
92 |
|
|
|
96 |
|
97 |
# inspect the parameters
|
98 |
if pprint==True:
|
99 |
+
# output_msg.append(f"Marginal income equation Y = {a} * x - {b} * x^2 + {c} * x^3 + {d}")
|
100 |
+
output_msg.append(f"Marginal income equation Y = {a} * x - {b} * x^2 + {c} * x^3")
|
101 |
|
102 |
# calculate max costs when it becomes negative ROAS
|
103 |
+
# df_marginal = pd.DataFrame(zip(np.arange(500000),
|
104 |
+
# polynomial_func(np.arange(500000), a,b,c,d)
|
105 |
+
# )).rename(columns={0:'cumulative_cost',1:'marginal_income'})
|
106 |
df_marginal = pd.DataFrame(zip(np.arange(500000),
|
107 |
+
polynomial_func(np.arange(500000), a,b,c)
|
108 |
+
)).rename(columns={0:'cumulative_cost',1:'marginal_income'})
|
109 |
# join actuals to get the full picture
|
110 |
_ = df_temp[['cost','cpc','cum_cost', 'cum_clicks', 'cum_cpc', 'cum_revenue', 'cum_income']]
|
111 |
# converting cost to integer in order to join with the marginal dataset
|
|
|
146 |
output_msg.append(f"For this spend, marginal_cpc={marginal_cpc_HAS}, cumulative_clicks={cum_clicks_HAS}, Average_cpc={cum_cpc_HAS}, cumulative_revenue={cum_revenue_HAS}")
|
147 |
output_msg.append(f"Total amount spent in negative ROAS={total_negative_roas_spend}")
|
148 |
# print (output_msg)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
149 |
else:
|
150 |
marginal_cpc,cum_clicks,cum_cpc,cum_revenue = np.nan, np.nan, np.nan, np.nan
|
151 |
total_negative_roas_spend=np.nan
|
152 |
if pprint==True:
|
153 |
+
output_msg.append(f"Not enough data for mCPC analysis. Max threshold resulted in {max_spend_threshold}. Highest amount spent during this period is: {highest_amount_spent}")
|
154 |
print (f"Not enough data for mCPC analysis. Max threshold resulted in {max_spend_threshold}. Highest amount spent during this period is: {highest_amount_spent}")
|
155 |
+
try:
|
156 |
+
ax1 = fig.add_subplot(121);
|
157 |
+
plt.scatter(df_temp['cum_cost'],df_temp['cpc'],color='black');
|
158 |
+
plt.axhline(1*cvr*aov,color='red',linestyle='--');plt.axhline(1*cvr*aov*pc,color='blue',linestyle='--');
|
159 |
+
plt.annotate(f'Any clicks above {np.round(cvr*aov,2)} SEK cpc has negative ROAS \n Above {np.round(cvr*aov*pc,2)} SEK is negative PC',size=12,xy=[0,40], color="black")
|
160 |
+
plt.xlabel('Cumulative ad spend that month (in SEK)'); plt.ylabel('Cost per individual click (in SEK)')
|
161 |
+
# ax2.axes.get_xaxis().set_visible(False)
|
162 |
+
ax1.title.set_text('CPC for at different spend levels');
|
163 |
+
except:
|
164 |
+
pass
|
165 |
+
try:
|
166 |
+
ax2 = fig.add_subplot(122)
|
167 |
+
plt.plot(df_temp['cum_cost'],df_temp['marginal_income'], '.', label="data", color='r')
|
168 |
+
# plt.plot(df_temp['cum_cost'], polynomial_func(df_temp['cum_cost'], a,b,c,d), '--', color='blue', label="fitted")
|
169 |
+
plt.plot(df_temp['cum_cost'], polynomial_func(df_temp['cum_cost'], a,b,c), '--', color='blue', label="fitted")
|
170 |
+
plt.xlabel('cumulative cost'); plt.ylabel('marginal income')
|
171 |
+
ax2.title.set_text('Net income at different spend levels')
|
172 |
+
except:
|
173 |
+
pass
|
174 |
values = (max_spend_threshold,highest_amount_spent,total_negative_roas_spend,marginal_cpc,cum_clicks,cum_cpc,cum_revenue,rSquared)
|
175 |
return fig,output_msg,values
|
176 |
+
# return fig,output_msg,values,df_marginal
|
177 |
|
178 |
def loop_mCPC_countries(df,min_date,max_date,
|
179 |
country_list=['UK', 'DE', 'US', 'NL', 'SE', 'CH', 'BE', 'EU', 'FR', 'AU'],
|