Spaces:
Sleeping
Sleeping
Pragya Jatav
commited on
Commit
·
7202334
1
Parent(s):
8351d98
test1
Browse files- Model_Result_Overview.py +124 -133
- README.md +1 -1
- Test/scenario_test_df.csv +104 -104
- __pycache__/utilities.cpython-310.pyc +0 -0
- __pycache__/utilities_with_panel.cpython-310.pyc +0 -0
- pages/8_Scenario_Planner.py +309 -342
- summary_df.pkl +2 -2
- utilities.py +5 -0
- utilities_with_panel.py +18 -18
Model_Result_Overview.py
CHANGED
@@ -1,12 +1,3 @@
|
|
1 |
-
'''
|
2 |
-
MMO Build Sprint 3
|
3 |
-
additions : contributions calculated using tuned Mixed LM model
|
4 |
-
pending : contributions calculations using - 1. not tuned Mixed LM model, 2. tuned OLS model, 3. not tuned OLS model
|
5 |
-
|
6 |
-
MMO Build Sprint 4
|
7 |
-
additions : response metrics selection
|
8 |
-
pending : contributions calculations using - 1. not tuned Mixed LM model, 2. tuned OLS model, 3. not tuned OLS model
|
9 |
-
'''
|
10 |
|
11 |
import streamlit as st
|
12 |
import pandas as pd
|
@@ -38,175 +29,175 @@ load_local_css('styles.css')
|
|
38 |
set_header()
|
39 |
|
40 |
|
41 |
-
|
42 |
-
|
43 |
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
|
50 |
-
|
51 |
|
52 |
|
53 |
-
|
54 |
-
|
55 |
|
56 |
-
|
57 |
-
|
58 |
|
59 |
-
|
60 |
-
|
61 |
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
|
79 |
-
|
80 |
|
81 |
|
82 |
-
|
83 |
-
|
84 |
|
85 |
-
#
|
86 |
-
#
|
87 |
-
#
|
88 |
-
|
89 |
-
|
90 |
|
91 |
-
#
|
92 |
|
93 |
-
|
94 |
|
95 |
-
#
|
96 |
-
|
97 |
-
|
98 |
|
99 |
-
|
100 |
-
|
101 |
|
102 |
-
|
103 |
|
104 |
-
|
105 |
-
|
106 |
|
107 |
-
|
108 |
-
|
109 |
|
110 |
-
|
111 |
-
|
112 |
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
|
117 |
-
|
118 |
-
|
119 |
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
|
126 |
-
|
127 |
|
128 |
-
|
129 |
-
|
130 |
|
131 |
-
|
132 |
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
|
138 |
-
|
139 |
-
|
140 |
|
141 |
|
142 |
-
|
143 |
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
|
149 |
|
150 |
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
#
|
155 |
-
#
|
156 |
-
|
157 |
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
|
164 |
|
165 |
-
|
166 |
-
|
167 |
|
168 |
-
|
169 |
-
#
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
|
181 |
-
|
182 |
-
|
183 |
|
184 |
-
|
185 |
-
|
186 |
|
187 |
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
|
193 |
-
|
194 |
-
|
195 |
|
196 |
-
|
197 |
|
198 |
-
|
199 |
|
200 |
-
#
|
201 |
-
#
|
202 |
|
203 |
-
#
|
204 |
-
#
|
205 |
-
#
|
206 |
-
#
|
207 |
-
#
|
208 |
-
#
|
209 |
-
#
|
210 |
-
#
|
211 |
-
#
|
212 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
|
2 |
import streamlit as st
|
3 |
import pandas as pd
|
|
|
29 |
set_header()
|
30 |
|
31 |
|
32 |
+
def get_random_effects(media_data, panel_col, mdf):
|
33 |
+
random_eff_df = pd.DataFrame(columns=[panel_col, "random_effect"])
|
34 |
|
35 |
+
for i, market in enumerate(media_data[panel_col].unique()):
|
36 |
+
print(i, end='\r')
|
37 |
+
intercept = mdf.random_effects[market].values[0]
|
38 |
+
random_eff_df.loc[i, 'random_effect'] = intercept
|
39 |
+
random_eff_df.loc[i, panel_col] = market
|
40 |
|
41 |
+
return random_eff_df
|
42 |
|
43 |
|
44 |
+
def process_train_and_test(train, test, features, panel_col, target_col):
|
45 |
+
X1 = train[features]
|
46 |
|
47 |
+
ss = MinMaxScaler()
|
48 |
+
X1 = pd.DataFrame(ss.fit_transform(X1), columns=X1.columns)
|
49 |
|
50 |
+
X1[panel_col] = train[panel_col]
|
51 |
+
X1[target_col] = train[target_col]
|
52 |
|
53 |
+
if test is not None:
|
54 |
+
X2 = test[features]
|
55 |
+
X2 = pd.DataFrame(ss.transform(X2), columns=X2.columns)
|
56 |
+
X2[panel_col] = test[panel_col]
|
57 |
+
X2[target_col] = test[target_col]
|
58 |
+
return X1, X2
|
59 |
+
return X1
|
60 |
|
61 |
+
def mdf_predict(X_df, mdf, random_eff_df) :
|
62 |
+
X=X_df.copy()
|
63 |
+
X=pd.merge(X, random_eff_df[[panel_col,'random_effect']], on=panel_col, how='left')
|
64 |
+
X['pred_fixed_effect'] = mdf.predict(X)
|
65 |
|
66 |
+
X['pred'] = X['pred_fixed_effect'] + X['random_effect']
|
67 |
+
X.to_csv('Test/merged_df_contri.csv',index=False)
|
68 |
+
X.drop(columns=['pred_fixed_effect', 'random_effect'], inplace=True)
|
69 |
|
70 |
+
return X
|
71 |
|
72 |
|
73 |
+
target_col='Prospects'
|
74 |
+
target='Prospects'
|
75 |
|
76 |
+
# is_panel=False
|
77 |
+
# is_panel = st.session_state['is_panel']
|
78 |
+
#panel_col = [col.lower().replace('.','_').replace('@','_').replace(" ", "_").replace('-', '').replace(':', '').replace("__", "_") for col in st.session_state['bin_dict']['Panel Level 1'] ] [0]# set the panel column
|
79 |
+
panel_col='Panel'
|
80 |
+
date_col = 'date'
|
81 |
|
82 |
+
#st.write(media_data)
|
83 |
|
84 |
+
is_panel = True
|
85 |
|
86 |
+
# panel_col='markets'
|
87 |
+
date_col = 'date'
|
88 |
+
for k, v in st.session_state.items():
|
89 |
|
90 |
+
if k not in ['logout', 'login','config'] and not k.startswith('FormSubmitter'):
|
91 |
+
st.session_state[k] = v
|
92 |
|
93 |
+
authenticator = st.session_state.get('authenticator')
|
94 |
|
95 |
+
if authenticator is None:
|
96 |
+
authenticator = load_authenticator()
|
97 |
|
98 |
+
name, authentication_status, username = authenticator.login('Login', 'main')
|
99 |
+
auth_status = st.session_state['authentication_status']
|
100 |
|
101 |
+
if auth_status:
|
102 |
+
authenticator.logout('Logout', 'main')
|
103 |
|
104 |
+
is_state_initiaized = st.session_state.get('initialized',False)
|
105 |
+
if not is_state_initiaized:
|
106 |
+
a=1
|
107 |
|
108 |
+
def panel_fetch(file_selected):
|
109 |
+
raw_data_mmm_df = pd.read_excel(file_selected, sheet_name="RAW DATA MMM")
|
110 |
|
111 |
+
if "Panel" in raw_data_mmm_df.columns:
|
112 |
+
panel = list(set(raw_data_mmm_df["Panel"]))
|
113 |
+
else:
|
114 |
+
raw_data_mmm_df = None
|
115 |
+
panel = None
|
116 |
|
117 |
+
return panel
|
118 |
|
119 |
+
def rerun():
|
120 |
+
st.rerun()
|
121 |
|
122 |
+
metrics_selected='prospects'
|
123 |
|
124 |
+
file_selected = (
|
125 |
+
f"Overview_data_test_panel@#{metrics_selected}.xlsx"
|
126 |
+
)
|
127 |
+
panel_list = panel_fetch(file_selected)
|
128 |
|
129 |
+
if "selected_markets" not in st.session_state:
|
130 |
+
st.session_state['selected_markets']='DMA1'
|
131 |
|
132 |
|
133 |
+
st.header('Overview of previous spends')
|
134 |
|
135 |
+
selected_market= st.selectbox(
|
136 |
+
"Select Markets",
|
137 |
+
["Total Market"] + panel_list
|
138 |
+
)
|
139 |
|
140 |
|
141 |
|
142 |
+
initialize_data(target_col,selected_market)
|
143 |
+
scenario = st.session_state['scenario']
|
144 |
+
raw_df = st.session_state['raw_df']
|
145 |
+
# st.write(scenario.actual_total_spends)
|
146 |
+
# st.write(scenario.actual_total_sales)
|
147 |
+
columns = st.columns((1,1,3))
|
148 |
|
149 |
+
with columns[0]:
|
150 |
+
st.metric(label='Spends', value=format_numbers(float(scenario.actual_total_spends)))
|
151 |
+
###print(f"##################### {scenario.actual_total_sales} ##################")
|
152 |
+
with columns[1]:
|
153 |
+
st.metric(label=target, value=format_numbers(float(scenario.actual_total_sales),include_indicator=False))
|
154 |
|
155 |
|
156 |
+
actual_summary_df = create_channel_summary(scenario)
|
157 |
+
actual_summary_df['Channel'] = actual_summary_df['Channel'].apply(channel_name_formating)
|
158 |
|
159 |
+
columns = st.columns((2,1))
|
160 |
+
#with columns[0]:
|
161 |
+
with st.expander('Channel wise overview'):
|
162 |
+
st.markdown(actual_summary_df.style.set_table_styles(
|
163 |
+
[{
|
164 |
+
'selector': 'th',
|
165 |
+
'props': [('background-color', '#FFFFF')]
|
166 |
+
},
|
167 |
+
{
|
168 |
+
'selector' : 'tr:nth-child(even)',
|
169 |
+
'props' : [('background-color', '#FFFFF')]
|
170 |
+
}]).to_html(), unsafe_allow_html=True)
|
171 |
|
172 |
+
st.markdown("<hr>",unsafe_allow_html=True)
|
173 |
+
##############################
|
174 |
|
175 |
+
st.plotly_chart(create_contribution_pie(scenario),use_container_width=True)
|
176 |
+
st.markdown("<hr>",unsafe_allow_html=True)
|
177 |
|
178 |
|
179 |
+
################################3
|
180 |
+
st.plotly_chart(create_contribuion_stacked_plot(scenario),use_container_width=True)
|
181 |
+
st.markdown("<hr>",unsafe_allow_html=True)
|
182 |
+
#######################################
|
183 |
|
184 |
+
selected_channel_name = st.selectbox('Channel', st.session_state['channels_list'] + ['non media'], format_func=channel_name_formating)
|
185 |
+
selected_channel = scenario.channels.get(selected_channel_name,None)
|
186 |
|
187 |
+
st.plotly_chart(create_channel_spends_sales_plot(selected_channel), use_container_width=True)
|
188 |
|
189 |
+
st.markdown("<hr>",unsafe_allow_html=True)
|
190 |
|
191 |
+
# elif auth_status == False:
|
192 |
+
# st.error('Username/Password is incorrect')
|
193 |
|
194 |
+
# if auth_status != True:
|
195 |
+
# try:
|
196 |
+
# username_forgot_pw, email_forgot_password, random_password = authenticator.forgot_password('Forgot password')
|
197 |
+
# if username_forgot_pw:
|
198 |
+
# st.success('New password sent securely')
|
199 |
+
# # Random password to be transferred to user securely
|
200 |
+
# elif username_forgot_pw == False:
|
201 |
+
# st.error('Username not found')
|
202 |
+
# except Exception as e:
|
203 |
+
# st.error(e)
|
README.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
---
|
2 |
-
title:
|
3 |
emoji: 🏆
|
4 |
colorFrom: indigo
|
5 |
colorTo: pink
|
|
|
1 |
---
|
2 |
+
title: UOPX
|
3 |
emoji: 🏆
|
4 |
colorFrom: indigo
|
5 |
colorTo: pink
|
Test/scenario_test_df.csv
CHANGED
@@ -1,105 +1,105 @@
|
|
1 |
other_contributions,correction,sales
|
2 |
-
1,-890.
|
3 |
-
1,-475.
|
4 |
-
1,-3.
|
5 |
-
1,-55.
|
6 |
-
1,-556.
|
7 |
-
1,-798.
|
8 |
-
1,-831.
|
9 |
-
1,-747.
|
10 |
-
1,-420.
|
11 |
-
1,-271.
|
12 |
-
1,36.
|
13 |
-
1,301.
|
14 |
-
1,-149.
|
15 |
-
1,-178.
|
16 |
-
1,-344.
|
17 |
-
1,-230.
|
18 |
-
1,123.
|
19 |
-
1,-346.
|
20 |
-
1,-271.
|
21 |
-
1,-354.
|
22 |
-
1,-19.
|
23 |
-
1,280.
|
24 |
-
1,219.
|
25 |
-
1,781.
|
26 |
-
1,1294.
|
27 |
-
1,738.
|
28 |
-
1,796.
|
29 |
-
1,415.
|
30 |
-
1,786.
|
31 |
-
1,699.
|
32 |
-
1,539.
|
33 |
-
1,377.
|
34 |
-
1,-171.
|
35 |
-
1,2.
|
36 |
-
1,-34.
|
37 |
-
1,-232.
|
38 |
-
1,-468.
|
39 |
-
1,-322.
|
40 |
-
1,-286.
|
41 |
-
1,-567.
|
42 |
-
1,-178.
|
43 |
-
1,-138.
|
44 |
-
1,-224.
|
45 |
-
1,792.
|
46 |
-
1,1355.
|
47 |
-
1,986.
|
48 |
-
1,1059.
|
49 |
-
1,383.
|
50 |
-
1,-187.
|
51 |
-
1,-212.
|
52 |
-
1,72.
|
53 |
-
1,-95.
|
54 |
-
1,-120.
|
55 |
-
1,-129.
|
56 |
-
1,-225.
|
57 |
-
1,-218.
|
58 |
-
1,-527.
|
59 |
-
1,-787.
|
60 |
-
1,-1039.
|
61 |
-
1,-753.
|
62 |
-
1,-357.
|
63 |
-
1,-324.
|
64 |
-
1,-133.
|
65 |
-
1,-45.
|
66 |
-
1,-198.
|
67 |
-
1,-140.
|
68 |
-
1,-328.
|
69 |
-
1,-471.
|
70 |
-
1,-340.
|
71 |
-
1,-451.
|
72 |
-
1,-470.
|
73 |
-
1,-241.
|
74 |
-
1,208.
|
75 |
-
1,515.
|
76 |
-
1,645.
|
77 |
-
1,600.
|
78 |
-
1,991.
|
79 |
-
1,1013.
|
80 |
-
1,917.
|
81 |
-
1,1015.
|
82 |
-
1,696.
|
83 |
-
1,847.
|
84 |
-
1,306.
|
85 |
-
1,584.
|
86 |
-
1,320.
|
87 |
-
1,90.
|
88 |
-
1,403.
|
89 |
-
1,83.
|
90 |
-
1,-278.
|
91 |
-
1,-594.
|
92 |
-
1,-638.
|
93 |
-
1,-820.
|
94 |
-
1,-777.
|
95 |
-
1,-937.
|
96 |
-
1,-766.
|
97 |
-
1,-601.
|
98 |
-
1,-43.
|
99 |
-
1,783.
|
100 |
-
1,1048.
|
101 |
-
1,942.
|
102 |
-
1,459.
|
103 |
-
1,-457.
|
104 |
-
1,-547.
|
105 |
-
1,-1007.
|
|
|
1 |
other_contributions,correction,sales
|
2 |
+
1,-890.9083269913208,5690.218095071322
|
3 |
+
1,-475.04172715926325,5552.575607149263
|
4 |
+
1,-3.0084997762223793,5560.943568626222
|
5 |
+
1,-55.835992656835515,5425.282497616836
|
6 |
+
1,-556.3423571615149,5516.629386071515
|
7 |
+
1,-798.7293276068531,5445.739089056853
|
8 |
+
1,-831.8661367345003,5200.4253466845
|
9 |
+
1,-747.1985886525281,5374.302970882529
|
10 |
+
1,-420.26596056385733,5332.913056923857
|
11 |
+
1,-271.1869770058056,5319.342549515806
|
12 |
+
1,36.61704801202177,5391.429887731978
|
13 |
+
1,301.40268262302834,5389.612139710971
|
14 |
+
1,-149.4327829167596,5242.93423795676
|
15 |
+
1,-178.18371062845563,5131.547398718455
|
16 |
+
1,-344.31242848795137,5289.838616957952
|
17 |
+
1,-230.8534688342088,5451.796660734209
|
18 |
+
1,123.81965248641245,5218.377356663587
|
19 |
+
1,-346.37018641133545,5376.028569331336
|
20 |
+
1,-271.2351337049313,5328.863885024932
|
21 |
+
1,-354.554715570026,5403.077810960025
|
22 |
+
1,-19.42185301387599,5485.364920013876
|
23 |
+
1,280.9211846086464,5590.702815091353
|
24 |
+
1,219.92735776987683,5516.867885530122
|
25 |
+
1,781.0334815120623,5679.809801587939
|
26 |
+
1,1294.2147923458106,5794.62514015419
|
27 |
+
1,738.501471567386,5867.577001832614
|
28 |
+
1,796.9528952899409,5766.399026290058
|
29 |
+
1,415.426998269626,5870.755899660374
|
30 |
+
1,786.9046031624202,5653.93211614758
|
31 |
+
1,699.8259613792034,5780.4945612307965
|
32 |
+
1,539.745101025057,5709.584150782943
|
33 |
+
1,377.1008301603306,5701.305955438669
|
34 |
+
1,-171.62603119793766,5654.003287164937
|
35 |
+
1,2.582553312521668,5483.3585810364775
|
36 |
+
1,-34.22562033747363,5514.875846412473
|
37 |
+
1,-232.94753657288948,5380.036090195889
|
38 |
+
1,-468.2093499173443,5549.191483465345
|
39 |
+
1,-322.5520717213203,5460.3946979333205
|
40 |
+
1,-286.06881459022316,4870.059378248223
|
41 |
+
1,-567.8495337345976,5126.330691409597
|
42 |
+
1,-178.17958404447836,4755.834189569478
|
43 |
+
1,-138.0179383988425,4914.4588403388425
|
44 |
+
1,-224.74888886520512,5285.073225435204
|
45 |
+
1,792.8627605627134,5620.162487447287
|
46 |
+
1,1355.6289643675454,6164.484521602455
|
47 |
+
1,986.2797608661913,6162.196124983808
|
48 |
+
1,1059.455769237742,6192.769529952258
|
49 |
+
1,383.32346060172495,6147.518456028276
|
50 |
+
1,-187.89672830752534,5715.406060937526
|
51 |
+
1,-212.61946644455293,5361.829613484553
|
52 |
+
1,72.72524427662756,5103.391602309372
|
53 |
+
1,-95.74246649852375,5238.581337104524
|
54 |
+
1,-120.67574389038145,5559.6276727923805
|
55 |
+
1,-129.05511796418978,5484.72889985719
|
56 |
+
1,-225.81656994822333,5494.042520330224
|
57 |
+
1,-218.3729272379751,5302.365695685976
|
58 |
+
1,-527.1306773658152,5229.707354409815
|
59 |
+
1,-787.2566332929828,5426.519151763983
|
60 |
+
1,-1039.0776762177748,5539.477859049774
|
61 |
+
1,-753.3501980635592,5429.758980752559
|
62 |
+
1,-357.5844211273052,5439.306041177304
|
63 |
+
1,-324.8985270979465,5678.245679517946
|
64 |
+
1,-133.5001332835127,5695.581704533513
|
65 |
+
1,-45.999364494504334,5662.909688574504
|
66 |
+
1,-198.8982053530026,5516.533581953001
|
67 |
+
1,-140.84226664971084,5403.844047839711
|
68 |
+
1,-328.0694341550152,5409.443929865015
|
69 |
+
1,-471.0469150562021,5319.741307806202
|
70 |
+
1,-340.9581299499314,4979.624243809932
|
71 |
+
1,-451.5102744182759,4939.252369518276
|
72 |
+
1,-470.3738494522695,5272.673163112269
|
73 |
+
1,-241.20911973847979,5185.85509377848
|
74 |
+
1,208.8574132962849,5444.731311283715
|
75 |
+
1,515.8201019324006,5531.571609717599
|
76 |
+
1,645.0637292085712,5567.486440531428
|
77 |
+
1,600.0432433501528,5726.386967019846
|
78 |
+
1,991.718208446463,5546.432488283537
|
79 |
+
1,1013.1534153918865,5402.554699058114
|
80 |
+
1,917.9498416432871,5331.587882096714
|
81 |
+
1,1015.0218196550877,5173.547445494913
|
82 |
+
1,696.1648921444839,5336.375056005516
|
83 |
+
1,847.2335698491934,5141.959263320808
|
84 |
+
1,306.98931138977787,5080.857405947222
|
85 |
+
1,584.0043413540361,4984.766656686964
|
86 |
+
1,320.81565350241544,4936.522939377584
|
87 |
+
1,90.34779668819192,5252.465610906807
|
88 |
+
1,403.10225090216045,5224.36913916284
|
89 |
+
1,83.73958567298178,5191.899359654019
|
90 |
+
1,-278.22837426408205,5013.4219235420815
|
91 |
+
1,-594.5906903171744,5002.829538211175
|
92 |
+
1,-638.5744723089219,4758.680377859922
|
93 |
+
1,-820.1630688997875,5052.951763736787
|
94 |
+
1,-777.5222929965912,5052.983144825591
|
95 |
+
1,-937.3473140298447,5133.260108853845
|
96 |
+
1,-766.0759176046422,5175.758653442641
|
97 |
+
1,-601.9624005578062,5336.127374237805
|
98 |
+
1,-43.38206579649068,5912.821508406491
|
99 |
+
1,783.5557775286761,5872.092495641323
|
100 |
+
1,1048.3380060975596,5779.24874920244
|
101 |
+
1,942.7156660498758,5657.687045620124
|
102 |
+
1,459.9194845831371,5422.163026676863
|
103 |
+
1,-457.0944462735897,5375.19352051359
|
104 |
+
1,-547.8520567101305,4949.85955425913
|
105 |
+
1,-1007.0066006714123,5301.205921773412
|
__pycache__/utilities.cpython-310.pyc
CHANGED
Binary files a/__pycache__/utilities.cpython-310.pyc and b/__pycache__/utilities.cpython-310.pyc differ
|
|
__pycache__/utilities_with_panel.cpython-310.pyc
CHANGED
Binary files a/__pycache__/utilities_with_panel.cpython-310.pyc and b/__pycache__/utilities_with_panel.cpython-310.pyc differ
|
|
pages/8_Scenario_Planner.py
CHANGED
@@ -6,7 +6,7 @@ from collections import OrderedDict
|
|
6 |
from plotly.subplots import make_subplots
|
7 |
import plotly.graph_objects as go
|
8 |
from utilities import (
|
9 |
-
format_numbers,
|
10 |
load_local_css,
|
11 |
set_header,
|
12 |
initialize_data,
|
@@ -22,12 +22,13 @@ from yaml import SafeLoader
|
|
22 |
import re
|
23 |
import pandas as pd
|
24 |
import plotly.express as px
|
25 |
-
|
26 |
|
27 |
st.set_page_config(layout="wide")
|
28 |
load_local_css("styles.css")
|
29 |
set_header()
|
30 |
|
|
|
31 |
for k, v in st.session_state.items():
|
32 |
if k not in ["logout", "login", "config"] and not k.startswith("FormSubmitter"):
|
33 |
st.session_state[k] = v
|
@@ -170,7 +171,7 @@ def update_all_spends_abs_slider():
|
|
170 |
# actual_spends = _scenario.actual_total_spends
|
171 |
# if validate_input(st.session_state["total_spends_change_abs_slider"]):
|
172 |
# print("#" * 100)
|
173 |
-
# print(st.session_state["total_spends_change_abs_slider"])
|
174 |
# print("#" * 100)
|
175 |
|
176 |
# modified_spends = extract_number_for_string(
|
@@ -493,192 +494,40 @@ def debug_temp(x_test, power, K, b, a, x0):
|
|
493 |
|
494 |
|
495 |
# @st.cache
|
496 |
-
def plot_response_curves():
|
497 |
-
cols =
|
498 |
-
rows = (
|
499 |
-
|
500 |
-
|
501 |
-
|
502 |
-
)
|
503 |
-
rcs = st.session_state["rcs"]
|
504 |
-
shapes = []
|
505 |
-
fig = make_subplots(rows=rows, cols=cols, subplot_titles=channels_list)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
506 |
for i in range(0, len(channels_list)):
|
507 |
col = channels_list[i]
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
|
514 |
-
|
515 |
-
a = rcs[col]["a"]
|
516 |
-
x0 = rcs[col]["x0"]
|
517 |
-
|
518 |
-
x_plot = np.linspace(0, 5 * x_actual.sum(), 50)
|
519 |
-
|
520 |
-
x, y, marginal_roi = [], [], []
|
521 |
-
for x_p in x_plot:
|
522 |
-
x.append(x_p * x_actual / x_actual.sum())
|
523 |
-
|
524 |
-
for index in range(len(x_plot)):
|
525 |
-
y.append(s_curve(x[index] / 10**power, K, b, a, x0))
|
526 |
-
|
527 |
-
for index in range(len(x_plot)):
|
528 |
-
marginal_roi.append(
|
529 |
-
a * y[index] * (1 - y[index] / np.maximum(K, np.finfo(float).eps))
|
530 |
-
)
|
531 |
-
|
532 |
-
x = (
|
533 |
-
np.sum(x, axis=1)
|
534 |
-
* st.session_state["scenario"].channels[col].conversion_rate
|
535 |
-
)
|
536 |
-
y = np.sum(y, axis=1)
|
537 |
-
marginal_roi = (
|
538 |
-
np.average(marginal_roi, axis=1)
|
539 |
-
/ st.session_state["scenario"].channels[col].conversion_rate
|
540 |
-
)
|
541 |
-
|
542 |
-
roi = y / np.maximum(x, np.finfo(float).eps)
|
543 |
-
|
544 |
-
fig.add_trace(
|
545 |
-
go.Scatter(
|
546 |
-
x=x,
|
547 |
-
y=y,
|
548 |
-
name=col,
|
549 |
-
customdata=np.stack((roi, marginal_roi), axis=-1),
|
550 |
-
hovertemplate="Spend:%{x:$.2s}<br>Sale:%{y:$.2s}<br>ROI:%{customdata[0]:.3f}<br>MROI:%{customdata[1]:.3f}",
|
551 |
-
line=dict(color="blue"),
|
552 |
-
),
|
553 |
-
row=1 + (i) // cols,
|
554 |
-
col=i % cols + 1,
|
555 |
-
)
|
556 |
-
|
557 |
-
x_optimal = (
|
558 |
-
st.session_state["scenario"].channels[col].modified_total_spends
|
559 |
-
* st.session_state["scenario"].channels[col].conversion_rate
|
560 |
-
)
|
561 |
-
y_optimal = st.session_state["scenario"].channels[col].modified_total_sales
|
562 |
-
|
563 |
-
# if col == "Paid_social_others":
|
564 |
-
# debug_temp(x_optimal * x_actual / x_actual.sum(), power, K, b, a, x0)
|
565 |
-
|
566 |
-
fig.add_trace(
|
567 |
-
go.Scatter(
|
568 |
-
x=[x_optimal],
|
569 |
-
y=[y_optimal],
|
570 |
-
name=col,
|
571 |
-
legendgroup=col,
|
572 |
-
showlegend=False,
|
573 |
-
marker=dict(color=["black"]),
|
574 |
-
),
|
575 |
-
row=1 + (i) // cols,
|
576 |
-
col=i % cols + 1,
|
577 |
-
)
|
578 |
-
|
579 |
-
shapes.append(
|
580 |
-
go.layout.Shape(
|
581 |
-
type="line",
|
582 |
-
x0=0,
|
583 |
-
y0=y_optimal,
|
584 |
-
x1=x_optimal,
|
585 |
-
y1=y_optimal,
|
586 |
-
line_width=1,
|
587 |
-
line_dash="dash",
|
588 |
-
line_color="black",
|
589 |
-
xref=f"x{i+1}",
|
590 |
-
yref=f"y{i+1}",
|
591 |
-
)
|
592 |
-
)
|
593 |
-
|
594 |
-
shapes.append(
|
595 |
-
go.layout.Shape(
|
596 |
-
type="line",
|
597 |
-
x0=x_optimal,
|
598 |
-
y0=0,
|
599 |
-
x1=x_optimal,
|
600 |
-
y1=y_optimal,
|
601 |
-
line_width=1,
|
602 |
-
line_dash="dash",
|
603 |
-
line_color="black",
|
604 |
-
xref=f"x{i+1}",
|
605 |
-
yref=f"y{i+1}",
|
606 |
-
)
|
607 |
-
)
|
608 |
-
|
609 |
-
start_value, end_value, left_value, right_value = find_segment_value(
|
610 |
-
x,
|
611 |
-
roi,
|
612 |
-
marginal_roi,
|
613 |
-
)
|
614 |
-
|
615 |
-
# Adding background colors
|
616 |
-
y_max = y.max() * 1.3 # 30% extra space above the max
|
617 |
-
|
618 |
-
# Yellow region
|
619 |
-
shapes.append(
|
620 |
-
go.layout.Shape(
|
621 |
-
type="rect",
|
622 |
-
x0=start_value,
|
623 |
-
y0=0,
|
624 |
-
x1=left_value,
|
625 |
-
y1=y_max,
|
626 |
-
line=dict(width=0),
|
627 |
-
fillcolor="rgba(255, 255, 0, 0.3)",
|
628 |
-
layer="below",
|
629 |
-
xref=f"x{i+1}",
|
630 |
-
yref=f"y{i+1}",
|
631 |
-
)
|
632 |
-
)
|
633 |
-
|
634 |
-
# Green region
|
635 |
-
shapes.append(
|
636 |
-
go.layout.Shape(
|
637 |
-
type="rect",
|
638 |
-
x0=left_value,
|
639 |
-
y0=0,
|
640 |
-
x1=right_value,
|
641 |
-
y1=y_max,
|
642 |
-
line=dict(width=0),
|
643 |
-
fillcolor="rgba(0, 255, 0, 0.3)",
|
644 |
-
layer="below",
|
645 |
-
xref=f"x{i+1}",
|
646 |
-
yref=f"y{i+1}",
|
647 |
-
)
|
648 |
-
)
|
649 |
-
|
650 |
-
# Red region
|
651 |
-
shapes.append(
|
652 |
-
go.layout.Shape(
|
653 |
-
type="rect",
|
654 |
-
x0=right_value,
|
655 |
-
y0=0,
|
656 |
-
x1=end_value,
|
657 |
-
y1=y_max,
|
658 |
-
line=dict(width=0),
|
659 |
-
fillcolor="rgba(255, 0, 0, 0.3)",
|
660 |
-
layer="below",
|
661 |
-
xref=f"x{i+1}",
|
662 |
-
yref=f"y{i+1}",
|
663 |
-
)
|
664 |
-
)
|
665 |
-
|
666 |
-
fig.update_layout(
|
667 |
-
# height=1000,
|
668 |
-
# width=1000,
|
669 |
-
title_text=f"Response Curves (X: Spends Vs Y: {target})",
|
670 |
-
showlegend=False,
|
671 |
-
shapes=shapes,
|
672 |
-
)
|
673 |
-
fig.update_annotations(font_size=10)
|
674 |
-
# fig.update_xaxes(title="Spends")
|
675 |
-
# fig.update_yaxes(title=target)
|
676 |
-
fig.update_yaxes(
|
677 |
-
gridcolor="rgba(136, 136, 136, 0.5)", gridwidth=0.5, griddash="dash"
|
678 |
-
)
|
679 |
-
|
680 |
-
return fig
|
681 |
-
|
682 |
|
683 |
# @st.cache
|
684 |
# def plot_response_curves():
|
@@ -849,7 +698,7 @@ def name_formating(channel_name):
|
|
849 |
return name_mod
|
850 |
|
851 |
|
852 |
-
|
853 |
def panel_fetch(file_selected):
|
854 |
raw_data_mmm_df = pd.read_excel(file_selected, sheet_name="RAW DATA MMM")
|
855 |
|
@@ -882,118 +731,174 @@ def reset_inputs():
|
|
882 |
|
883 |
if auth_status == True:
|
884 |
authenticator.logout("Logout", "main")
|
885 |
-
|
886 |
-
|
887 |
-
with st.expander('Optimized Spends Overview'):
|
888 |
-
if st.button('Refresh'):
|
889 |
-
st.rerun()
|
890 |
-
|
891 |
-
import plotly.graph_objects as go
|
892 |
-
from plotly.subplots import make_subplots
|
893 |
-
|
894 |
-
# Define light colors for bars
|
895 |
-
import plotly.graph_objects as go
|
896 |
-
from plotly.subplots import make_subplots
|
897 |
-
|
898 |
-
st.empty()
|
899 |
-
#st.header('Model Result Analysis')
|
900 |
-
spends_data=pd.read_excel('Overview_data_test.xlsx')
|
901 |
-
|
902 |
-
with open('summary_df.pkl', 'rb') as file:
|
903 |
-
summary_df_sorted = pickle.load(file)
|
904 |
-
#st.write(summary_df_sorted)
|
905 |
-
|
906 |
-
# selected_scenario= st.selectbox('Select Saved Scenarios',['S1','S2'])
|
907 |
-
summary_df_sorted=summary_df_sorted.sort_values(by=['Optimized_spend'],ascending=False)
|
908 |
-
summary_df_sorted['old_roi']=summary_df_sorted['Old_sales']/summary_df_sorted['Actual_spend']
|
909 |
-
summary_df_sorted['new_roi']=summary_df_sorted['New_sales']/summary_df_sorted['Optimized_spend']
|
910 |
-
|
911 |
-
total_actual_spend = summary_df_sorted['Actual_spend'].sum()
|
912 |
-
total_optimized_spend = summary_df_sorted['Optimized_spend'].sum()
|
913 |
-
|
914 |
-
actual_spend_percentage = (summary_df_sorted['Actual_spend'] / total_actual_spend) * 100
|
915 |
-
optimized_spend_percentage = (summary_df_sorted['Optimized_spend'] / total_optimized_spend) * 100
|
916 |
-
|
917 |
-
|
918 |
-
|
919 |
-
light_blue = 'rgba(0, 31, 120, 0.7)'
|
920 |
-
light_orange = 'rgba(0, 181, 219, 0.7)'
|
921 |
-
light_green = 'rgba(240, 61, 20, 0.7)'
|
922 |
-
light_red = 'rgba(250, 110, 10, 0.7)'
|
923 |
-
light_purple = 'rgba(255, 191, 69, 0.7)'
|
924 |
-
|
925 |
-
|
926 |
-
# Create subplots with one row and two columns
|
927 |
-
fig = make_subplots(rows=1, cols=3, subplot_titles=("Actual vs. Optimized Spend", "Actual vs. Optimized Contribution", "Actual vs. Optimized ROI"))
|
928 |
-
|
929 |
-
# Add actual vs optimized spend bars
|
930 |
-
|
931 |
-
|
932 |
-
fig.add_trace(go.Bar(y=summary_df_sorted['Channel_name'], x=summary_df_sorted['Actual_spend'], name='Actual',
|
933 |
-
text=summary_df_sorted['Actual_spend'].apply(format_number) + ' '+' (' + actual_spend_percentage.round(2).astype(str) + '%)',
|
934 |
-
marker_color=light_blue, orientation='h'),
|
935 |
-
row=1,
|
936 |
-
col=1)
|
937 |
-
|
938 |
|
939 |
-
|
940 |
-
|
941 |
-
|
942 |
-
|
943 |
-
|
944 |
-
|
945 |
-
|
946 |
-
|
947 |
-
|
948 |
-
|
949 |
-
|
950 |
-
|
951 |
-
|
952 |
-
|
953 |
-
|
954 |
-
|
955 |
-
|
956 |
-
|
957 |
-
|
958 |
-
|
959 |
-
|
960 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
961 |
|
962 |
-
|
963 |
-
name='Optimized ROI',text=summary_df_sorted['new_roi'].apply(format_number) ,
|
964 |
-
marker_color=light_orange, orientation='h',showlegend=False), row=1, col=3)
|
965 |
-
|
966 |
-
fig.add_trace(go.Bar(y=summary_df_sorted['Channel_name'], x=summary_df_sorted['old_roi'],
|
967 |
-
name='Actual ROI', text=summary_df_sorted['old_roi'].apply(format_number) ,
|
968 |
-
marker_color=light_blue, orientation='h',showlegend=False), row=1, col=3)
|
969 |
-
|
970 |
-
fig.update_xaxes(title_text="ROI", row=1, col=3)
|
971 |
-
|
972 |
-
# Update layout
|
973 |
-
fig.update_layout(title_text="Actual vs. Optimized Metrics for Media Channels",
|
974 |
-
showlegend=True, yaxis=dict(title='Media Channels', autorange="reversed"))
|
975 |
-
|
976 |
-
st.plotly_chart(fig,use_container_width=True)
|
977 |
|
978 |
-
# fig = make_subplots(rows=1, cols=2, subplot_titles=("Actual Spend", "Optimized Spend"), specs=[[{'type': 'domain'}, {'type': 'domain'}]])
|
979 |
-
|
980 |
-
# # Actual spend donut chart
|
981 |
-
# fig.add_trace(go.Pie(labels=summary_df_sorted['Channel_name'],
|
982 |
-
# values=summary_df_sorted['Actual_spend'], name='Actual Spend', hole=0.3,
|
983 |
-
# marker_colors=[light_blue, light_orange, light_green, light_red, light_purple]), row=1, col=1)
|
984 |
-
|
985 |
-
# # Optimized spend donut chart
|
986 |
-
# fig.add_trace(go.Pie(labels=summary_df_sorted['Channel_name'],
|
987 |
-
# values=summary_df_sorted['Optimized_spend'], name='Optimized Spend', hole=0.3,
|
988 |
-
# arker_colors=[light_blue, light_orange, light_green, light_red, light_purple]), row=1, col=2)
|
989 |
-
|
990 |
-
# # Update layout
|
991 |
-
# fig.update_layout(title_text="Actual vs. Optimized Spend Distribution")
|
992 |
-
|
993 |
-
# # Show plot
|
994 |
-
# st.plotly_chart(fig, use_container_width=True)
|
995 |
-
|
996 |
-
#col1, col2 = st.columns([1, 1])
|
997 |
|
998 |
# Response Metrics
|
999 |
directory = "metrics_level_data"
|
@@ -1018,14 +923,16 @@ if auth_status == True:
|
|
1018 |
# Panel List
|
1019 |
panel_list = panel_fetch(file_selected)
|
1020 |
|
1021 |
-
# Panel Selected
|
1022 |
-
panel_selected = st.selectbox(
|
1023 |
-
|
1024 |
-
|
1025 |
-
|
1026 |
-
|
1027 |
-
)
|
1028 |
|
|
|
|
|
1029 |
st.session_state['selected_markets']=panel_selected
|
1030 |
|
1031 |
if "update_rcs" in st.session_state:
|
@@ -1058,6 +965,15 @@ if auth_status == True:
|
|
1058 |
st.session_state["initialized"] = True
|
1059 |
st.session_state["first_time"] = False
|
1060 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1061 |
# Channels List
|
1062 |
channels_list = st.session_state["channels_list"]
|
1063 |
|
@@ -1108,7 +1024,7 @@ if auth_status == True:
|
|
1108 |
with sub_header[1]:
|
1109 |
st.metric(
|
1110 |
label=target,
|
1111 |
-
value=
|
1112 |
float(_scenario.actual_total_sales)
|
1113 |
),
|
1114 |
)
|
@@ -1123,7 +1039,7 @@ if auth_status == True:
|
|
1123 |
with sub_header[3]:
|
1124 |
st.metric(
|
1125 |
label=target,
|
1126 |
-
value=
|
1127 |
float(_scenario.modified_total_sales)
|
1128 |
),
|
1129 |
delta=numerize(_scenario.delta_sales, 1),
|
@@ -1169,8 +1085,11 @@ if auth_status == True:
|
|
1169 |
st.button(
|
1170 |
"Reset",
|
1171 |
on_click=reset_scenario,
|
1172 |
-
args=(panel_selected, file_selected, updated_rcs)
|
|
|
1173 |
)
|
|
|
|
|
1174 |
|
1175 |
_columns2 = st.columns((2, 2, 2))
|
1176 |
if st.session_state["optimization_key"] == "Media Spends":
|
@@ -1206,8 +1125,9 @@ if auth_status == True:
|
|
1206 |
# key="total_spends_change_abs_slider",
|
1207 |
# on_change=update_all_spends_abs_slider,
|
1208 |
# )
|
1209 |
-
|
1210 |
elif st.session_state["optimization_key"] == target:
|
|
|
1211 |
with _columns2[0]:
|
1212 |
sales_input = st.text_input(
|
1213 |
"Absolute",
|
@@ -1227,9 +1147,13 @@ if auth_status == True:
|
|
1227 |
with _columns2[2]:
|
1228 |
min_value = round(_scenario.actual_total_sales * 0.5)
|
1229 |
max_value = round(_scenario.actual_total_sales * 1.5)
|
|
|
|
|
|
|
|
|
1230 |
st.session_state["total_sales_change_abs_slider_options"] = [
|
1231 |
numerize(value, 1)
|
1232 |
-
for value in range(min_value, max_value + 1, int(
|
1233 |
]
|
1234 |
|
1235 |
st.select_slider(
|
@@ -1237,6 +1161,7 @@ if auth_status == True:
|
|
1237 |
options=st.session_state["total_sales_change_abs_slider_options"],
|
1238 |
key="total_sales_change_abs_slider",
|
1239 |
on_change=update_sales_abs_slider,
|
|
|
1240 |
)
|
1241 |
|
1242 |
if (
|
@@ -1261,7 +1186,7 @@ if auth_status == True:
|
|
1261 |
"Optimize",
|
1262 |
on_click=optimize,
|
1263 |
args=(st.session_state["optimization_key"], status_placeholder),
|
1264 |
-
use_container_width=True,
|
1265 |
)
|
1266 |
|
1267 |
st.markdown("""<hr class="spends-heading-seperator">""", unsafe_allow_html=True)
|
@@ -1289,6 +1214,7 @@ if auth_status == True:
|
|
1289 |
"Old_sales":[]
|
1290 |
}
|
1291 |
for i, channel_name in enumerate(channels_list):
|
|
|
1292 |
_channel_class = st.session_state["scenario"].channels[channel_name]
|
1293 |
_columns = st.columns((2.5, 1.5, 1.5, 1.5, 1))
|
1294 |
with _columns[0]:
|
@@ -1360,7 +1286,7 @@ if auth_status == True:
|
|
1360 |
|
1361 |
st.metric(
|
1362 |
target,
|
1363 |
-
|
1364 |
delta=numerize(sales_delta, 1),
|
1365 |
label_visibility="collapsed",
|
1366 |
)
|
@@ -1393,7 +1319,13 @@ if auth_status == True:
|
|
1393 |
col = channels_list[i]
|
1394 |
x_actual = st.session_state["scenario"].channels[col].actual_spends
|
1395 |
x_modified = st.session_state["scenario"].channels[col].modified_spends
|
1396 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
1397 |
x_total = x_modified.sum()
|
1398 |
power = np.ceil(np.log(x_actual.max()) / np.log(10)) - 3
|
1399 |
|
@@ -1438,9 +1370,13 @@ if auth_status == True:
|
|
1438 |
)
|
1439 |
|
1440 |
roi = y / np.maximum(x, np.finfo(float).eps)
|
|
|
|
|
|
|
|
|
1441 |
|
1442 |
-
#st.write(roi[-1])
|
1443 |
-
|
1444 |
roi_current, marginal_roi_current = roi[-1], marginal_roi[-1]
|
1445 |
x, y, roi, marginal_roi = (
|
1446 |
x[:-1],
|
@@ -1449,6 +1385,8 @@ if auth_status == True:
|
|
1449 |
marginal_roi[:-1],
|
1450 |
) # Drop data for current spends
|
1451 |
|
|
|
|
|
1452 |
start_value, end_value, left_value, right_value = find_segment_value(
|
1453 |
x,
|
1454 |
roi,
|
@@ -1465,6 +1403,25 @@ if auth_status == True:
|
|
1465 |
current_channel_spends,
|
1466 |
)
|
1467 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1468 |
with bin_placeholder:
|
1469 |
st.markdown(
|
1470 |
f"""
|
@@ -1475,41 +1432,33 @@ if auth_status == True:
|
|
1475 |
text-align: center;
|
1476 |
color: #006EC0;
|
1477 |
">
|
1478 |
-
<p style="margin: 0; font-size: 20px;">
|
1479 |
-
|
1480 |
</div>
|
1481 |
""",
|
1482 |
unsafe_allow_html=True,
|
1483 |
)
|
1484 |
|
1485 |
-
|
1486 |
-
|
1487 |
-
|
1488 |
-
|
1489 |
-
# _columns = st.columns(2)
|
1490 |
-
# # with _columns[0]:
|
1491 |
-
# st.subheader("Save Scenario")
|
1492 |
-
# scenario_name = st.text_input(
|
1493 |
-
# "Scenario name",
|
1494 |
-
# key="scenario_input",
|
1495 |
-
# placeholder="Scenario name",
|
1496 |
-
# label_visibility="collapsed",
|
1497 |
-
# )
|
1498 |
-
# st.button(
|
1499 |
-
# "Save",
|
1500 |
-
# on_click=lambda: save_scenario(scenario_name),
|
1501 |
-
# disabled=len(st.session_state["scenario_input"]) == 0,use_container_width=True
|
1502 |
-
# )
|
1503 |
|
1504 |
-
|
1505 |
-
#
|
|
|
|
|
1506 |
|
1507 |
-
|
1508 |
-
|
1509 |
-
|
1510 |
-
|
1511 |
-
|
1512 |
-
|
|
|
|
|
|
|
|
|
1513 |
|
1514 |
with open("summary_df.pkl", "wb") as f:
|
1515 |
pickle.dump(summary_df_sorted, f)
|
@@ -1525,6 +1474,24 @@ if auth_status == True:
|
|
1525 |
# fig=summary_plot(summary_df_sorted, x='Optimized_spend', y='Channel_name', title='Planned Spend', text_column='Optimized_spend')
|
1526 |
# st.plotly_chart(fig,use_container_width=True)
|
1527 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1528 |
|
1529 |
elif auth_status == False:
|
1530 |
st.error("Username/Password is incorrect")
|
|
|
6 |
from plotly.subplots import make_subplots
|
7 |
import plotly.graph_objects as go
|
8 |
from utilities import (
|
9 |
+
format_numbers,format_numbers_f,
|
10 |
load_local_css,
|
11 |
set_header,
|
12 |
initialize_data,
|
|
|
22 |
import re
|
23 |
import pandas as pd
|
24 |
import plotly.express as px
|
25 |
+
import response_curves_model_quality as rc
|
26 |
|
27 |
st.set_page_config(layout="wide")
|
28 |
load_local_css("styles.css")
|
29 |
set_header()
|
30 |
|
31 |
+
|
32 |
for k, v in st.session_state.items():
|
33 |
if k not in ["logout", "login", "config"] and not k.startswith("FormSubmitter"):
|
34 |
st.session_state[k] = v
|
|
|
171 |
# actual_spends = _scenario.actual_total_spends
|
172 |
# if validate_input(st.session_state["total_spends_change_abs_slider"]):
|
173 |
# print("#" * 100)
|
174 |
+
# print(st.session_state["total_spends_change_abs_slider"])C:\Users\PragyaJatav\Downloads\Untitled Folder 2\simulatorAldi\pages\8_Scenario_Planner.py
|
175 |
# print("#" * 100)
|
176 |
|
177 |
# modified_spends = extract_number_for_string(
|
|
|
494 |
|
495 |
|
496 |
# @st.cache
|
497 |
+
def plot_response_curves(summary_df_sorted):
|
498 |
+
# cols = 3
|
499 |
+
# rows = (
|
500 |
+
# len(channels_list) // cols
|
501 |
+
# if len(channels_list) % cols == 0
|
502 |
+
# else len(channels_list) // cols + 1
|
503 |
+
# )
|
504 |
+
# rcs = st.session_state["rcs"]
|
505 |
+
# shapes = []
|
506 |
+
# fig = make_subplots(rows=rows, cols=cols, subplot_titles=channels_list)
|
507 |
+
channel_cols = [
|
508 |
+
'BroadcastTV',
|
509 |
+
'CableTV',
|
510 |
+
'Connected&OTTTV',
|
511 |
+
'DisplayProspecting',
|
512 |
+
'DisplayRetargeting',
|
513 |
+
'Video',
|
514 |
+
'SocialProspecting',
|
515 |
+
'SocialRetargeting',
|
516 |
+
'SearchBrand',
|
517 |
+
'SearchNon-brand',
|
518 |
+
'DigitalPartners',
|
519 |
+
'Audio',
|
520 |
+
'Email']
|
521 |
+
summary_df_sorted.index = summary_df_sorted["Channel_name"]
|
522 |
for i in range(0, len(channels_list)):
|
523 |
col = channels_list[i]
|
524 |
+
if col == "Panel":
|
525 |
+
continue
|
526 |
+
st.write(col)
|
527 |
+
x_modified = summary_df_sorted["Optimized_spend"][col]/104
|
528 |
+
y_modified = summary_df_sorted["New_sales"][col]/104
|
529 |
+
st.plotly_chart(rc.response_curves(col,x_modified,y_modified))
|
530 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
531 |
|
532 |
# @st.cache
|
533 |
# def plot_response_curves():
|
|
|
698 |
return name_mod
|
699 |
|
700 |
|
701 |
+
@st.experimental_memo(show_spinner=False)
|
702 |
def panel_fetch(file_selected):
|
703 |
raw_data_mmm_df = pd.read_excel(file_selected, sheet_name="RAW DATA MMM")
|
704 |
|
|
|
731 |
|
732 |
if auth_status == True:
|
733 |
authenticator.logout("Logout", "main")
|
734 |
+
st.header("Scenario Planner")
|
735 |
+
def scenario_planner_plots():
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
736 |
|
737 |
+
with st.expander('Optimized Spends Overview'):
|
738 |
+
# if st.button('Refresh'):
|
739 |
+
# st.experimental_rerun()
|
740 |
+
|
741 |
+
import plotly.graph_objects as go
|
742 |
+
from plotly.subplots import make_subplots
|
743 |
+
|
744 |
+
# Define light colors for bars
|
745 |
+
import plotly.graph_objects as go
|
746 |
+
from plotly.subplots import make_subplots
|
747 |
+
|
748 |
+
st.empty()
|
749 |
+
#st.header('Model Result Analysis')
|
750 |
+
spends_data=pd.read_excel('Overview_data_test.xlsx')
|
751 |
+
|
752 |
+
with open('summary_df.pkl', 'rb') as file:
|
753 |
+
summary_df_sorted = pickle.load(file)
|
754 |
+
#st.write(summary_df_sorted)
|
755 |
+
|
756 |
+
# selected_scenario= st.selectbox('Select Saved Scenarios',['S1','S2'])
|
757 |
+
summary_df_sorted=summary_df_sorted.sort_values(by=['Optimized_spend'],ascending=False)
|
758 |
+
summary_df_sorted['old_efficiency']=(summary_df_sorted['Old_sales']/summary_df_sorted['Old_sales'].sum())/(summary_df_sorted['Actual_spend']/summary_df_sorted['Actual_spend'].sum())
|
759 |
+
summary_df_sorted['new_efficiency']=(summary_df_sorted['New_sales']/summary_df_sorted['New_sales'].sum())/(summary_df_sorted['Optimized_spend']/summary_df_sorted['Optimized_spend'].sum())
|
760 |
+
|
761 |
+
summary_df_sorted['old_roi']=summary_df_sorted['Old_sales']/summary_df_sorted['Actual_spend']
|
762 |
+
summary_df_sorted['new_roi']=summary_df_sorted['New_sales']/summary_df_sorted['Optimized_spend']
|
763 |
+
|
764 |
+
total_actual_spend = summary_df_sorted['Actual_spend'].sum()
|
765 |
+
total_optimized_spend = summary_df_sorted['Optimized_spend'].sum()
|
766 |
+
|
767 |
+
actual_spend_percentage = (summary_df_sorted['Actual_spend'] / total_actual_spend) * 100
|
768 |
+
optimized_spend_percentage = (summary_df_sorted['Optimized_spend'] / total_optimized_spend) * 100
|
769 |
+
|
770 |
+
|
771 |
+
|
772 |
+
light_blue = 'rgba(0, 31, 120, 0.7)'
|
773 |
+
light_orange = 'rgba(0, 181, 219, 0.7)'
|
774 |
+
light_green = 'rgba(240, 61, 20, 0.7)'
|
775 |
+
light_red = 'rgba(250, 110, 10, 0.7)'
|
776 |
+
light_purple = 'rgba(255, 191, 69, 0.7)'
|
777 |
+
|
778 |
+
|
779 |
+
# # Create subplots with one row and two columns
|
780 |
+
# fig = make_subplots(rows=3, cols=1, subplot_titles=("Actual vs. Optimized Spend", "Actual vs. Optimized Contribution", "Actual vs. Optimized ROI"))
|
781 |
+
|
782 |
+
# # Add actual vs optimized spend bars
|
783 |
+
|
784 |
+
|
785 |
+
# fig.add_trace(go.Bar(y=summary_df_sorted['Channel_name'], x=summary_df_sorted['Actual_spend'], name='Actual',
|
786 |
+
# text=summary_df_sorted['Actual_spend'].apply(format_number) + ' '+' (' + actual_spend_percentage.round(2).astype(str) + '%)',
|
787 |
+
# marker_color=light_blue, orientation='h'),
|
788 |
+
# row=1,
|
789 |
+
# col=1)
|
790 |
+
|
791 |
+
|
792 |
+
# fig.add_trace(go.Bar(y=summary_df_sorted['Channel_name'], x=summary_df_sorted['Optimized_spend'], name='Optimized',
|
793 |
+
# text=summary_df_sorted['Optimized_spend'].apply(format_number) + ' (' + optimized_spend_percentage.round(2).astype(str) + '%)',
|
794 |
+
# marker_color=light_orange,
|
795 |
+
# orientation='h'),
|
796 |
+
# row=1,
|
797 |
+
# col=1)
|
798 |
+
|
799 |
+
# fig.update_xaxes(title_text="Amount", row=1, col=1)
|
800 |
+
|
801 |
+
# # Add actual vs optimized Contribution
|
802 |
+
# fig.add_trace(go.Bar(y=summary_df_sorted['Channel_name'], x=summary_df_sorted['New_sales'],
|
803 |
+
# name='Optimized Contribution',text=summary_df_sorted['New_sales'].apply(format_number),
|
804 |
+
# marker_color=light_orange, orientation='h',showlegend=False), row=2, col=1)
|
805 |
+
|
806 |
+
# fig.add_trace(go.Bar(y=summary_df_sorted['Channel_name'], x=summary_df_sorted['Old_sales'],
|
807 |
+
# name='Actual Contribution',text=summary_df_sorted['Old_sales'].apply(format_number),
|
808 |
+
# marker_color=light_blue, orientation='h',showlegend=False), row=2, col=1)
|
809 |
+
|
810 |
+
|
811 |
+
# fig.update_xaxes(title_text="Contribution", row=2, col=1)
|
812 |
+
|
813 |
+
# # Add actual vs optimized ROI bars
|
814 |
+
|
815 |
+
# fig.add_trace(go.Bar(y=summary_df_sorted['Channel_name'], x=summary_df_sorted['new_roi'],
|
816 |
+
# name='Optimized ROI',text=summary_df_sorted['new_roi'].apply(format_number) ,
|
817 |
+
# marker_color=light_orange, orientation='h',showlegend=False), row=3, col=1)
|
818 |
+
|
819 |
+
# fig.add_trace(go.Bar(y=summary_df_sorted['Channel_name'], x=summary_df_sorted['old_roi'],
|
820 |
+
# name='Actual ROI', text=summary_df_sorted['old_roi'].apply(format_number) ,
|
821 |
+
# marker_color=light_blue, orientation='h',showlegend=False), row=3, col=1)
|
822 |
+
|
823 |
+
# fig.update_xaxes(title_text="ROI", row=3, col=1)
|
824 |
+
|
825 |
+
# # Update layout
|
826 |
+
# fig.update_layout(title_text="Actual vs. Optimized Metrics for Media Channels",
|
827 |
+
# showlegend=True, yaxis=dict(title='Media Channels', autorange="reversed"))
|
828 |
+
|
829 |
+
# st.plotly_chart(fig,use_container_width=True)
|
830 |
+
|
831 |
+
# Create subplots with one row and two columns
|
832 |
+
fig = go.Figure()
|
833 |
+
# Add actual vs optimized spend bars
|
834 |
+
|
835 |
+
|
836 |
+
fig.add_trace(go.Bar(x=summary_df_sorted['Channel_name'], y=summary_df_sorted['Actual_spend'], name='Actual',
|
837 |
+
text=summary_df_sorted['Actual_spend'].apply(format_number) + ' '
|
838 |
+
# +
|
839 |
+
# ' '+
|
840 |
+
# '</br> (' + actual_spend_percentage.astype(int).astype(str) + '%)'
|
841 |
+
,textposition='outside',#textfont=dict(size=30),
|
842 |
+
marker_color=light_blue))
|
843 |
+
|
844 |
+
|
845 |
+
fig.add_trace(go.Bar(x=summary_df_sorted['Channel_name'], y=summary_df_sorted['Optimized_spend'], name='Optimized',
|
846 |
+
text=summary_df_sorted['Optimized_spend'].apply(format_number) + ' '
|
847 |
+
# +
|
848 |
+
# '</br> (' + optimized_spend_percentage.astype(int).astype(str) + '%)'
|
849 |
+
,textposition='outside',#textfont=dict(size=30),
|
850 |
+
marker_color=light_orange))
|
851 |
+
|
852 |
+
fig.update_xaxes(title_text="Channels")
|
853 |
+
fig.update_yaxes(title_text="Spends ($)")
|
854 |
+
fig.update_layout(
|
855 |
+
title = "Actual vs. Optimized Spends",
|
856 |
+
margin=dict(t=40, b=40, l=40, r=40)
|
857 |
+
)
|
858 |
+
|
859 |
+
st.plotly_chart(fig,use_container_width=True)
|
860 |
+
|
861 |
+
# Add actual vs optimized Contribution
|
862 |
+
fig = go.Figure()
|
863 |
+
fig.add_trace(go.Bar(x=summary_df_sorted['Channel_name'], y=summary_df_sorted['Old_sales'],
|
864 |
+
name='Actual Contribution',text=summary_df_sorted['Old_sales'].apply(format_number),textposition='outside',
|
865 |
+
marker_color=light_blue,showlegend=True))
|
866 |
+
|
867 |
+
fig.add_trace(go.Bar(x=summary_df_sorted['Channel_name'], y=summary_df_sorted['New_sales'],
|
868 |
+
name='Optimized Contribution',text=summary_df_sorted['New_sales'].apply(format_number),textposition='outside',
|
869 |
+
marker_color=light_orange, showlegend=True))
|
870 |
+
|
871 |
+
|
872 |
+
|
873 |
+
fig.update_yaxes(title_text="Contribution")
|
874 |
+
fig.update_xaxes(title_text="Channels")
|
875 |
+
fig.update_layout(
|
876 |
+
title = "Actual vs. Optimized Contributions",
|
877 |
+
margin=dict(t=40, b=40, l=40, r=40)
|
878 |
+
# yaxis=dict(range=[0, 0.002]),
|
879 |
+
)
|
880 |
+
st.plotly_chart(fig,use_container_width=True)
|
881 |
+
|
882 |
+
# Add actual vs optimized Efficiency bars
|
883 |
+
fig = go.Figure()
|
884 |
+
summary_df_sorted_p = summary_df_sorted[summary_df_sorted['Channel_name']!="Panel"]
|
885 |
+
fig.add_trace(go.Bar(x=summary_df_sorted_p['Channel_name'], y=summary_df_sorted_p['old_efficiency'],
|
886 |
+
name='Actual Efficiency', text=summary_df_sorted_p['old_efficiency'].apply(format_number) ,textposition='outside',
|
887 |
+
marker_color=light_blue,showlegend=True))
|
888 |
+
fig.add_trace(go.Bar(x=summary_df_sorted_p['Channel_name'], y=summary_df_sorted_p['new_efficiency'],
|
889 |
+
name='Optimized Efficiency',text=summary_df_sorted_p['new_efficiency'].apply(format_number),textposition='outside' ,
|
890 |
+
marker_color=light_orange,showlegend=True))
|
891 |
+
|
892 |
+
fig.update_xaxes(title_text="Channels")
|
893 |
+
fig.update_yaxes(title_text="ROI")
|
894 |
+
fig.update_layout(
|
895 |
+
title = "Actual vs. Optimized ROI",
|
896 |
+
margin=dict(t=40, b=40, l=40, r=40),
|
897 |
+
# yaxis=dict(range=[0, 0.002]),
|
898 |
+
)
|
899 |
|
900 |
+
st.plotly_chart(fig,use_container_width=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
901 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
902 |
|
903 |
# Response Metrics
|
904 |
directory = "metrics_level_data"
|
|
|
923 |
# Panel List
|
924 |
panel_list = panel_fetch(file_selected)
|
925 |
|
926 |
+
# # Panel Selected
|
927 |
+
# panel_selected = st.selectbox(
|
928 |
+
# "Markets",
|
929 |
+
# ["Total Market"] + panel_list,
|
930 |
+
# index=0,
|
931 |
+
# on_change=reset_inputs,
|
932 |
+
# )
|
933 |
|
934 |
+
# st.write(panel_selected)
|
935 |
+
panel_selected = "Total Market"
|
936 |
st.session_state['selected_markets']=panel_selected
|
937 |
|
938 |
if "update_rcs" in st.session_state:
|
|
|
965 |
st.session_state["initialized"] = True
|
966 |
st.session_state["first_time"] = False
|
967 |
|
968 |
+
# initialize_data(
|
969 |
+
# panel=panel_selected,
|
970 |
+
# target_file=file_selected,
|
971 |
+
# updated_rcs=updated_rcs,
|
972 |
+
# metrics=metrics_selected,
|
973 |
+
# )
|
974 |
+
# st.session_state["initialized"] = True
|
975 |
+
# st.session_state["first_time"] = False
|
976 |
+
|
977 |
# Channels List
|
978 |
channels_list = st.session_state["channels_list"]
|
979 |
|
|
|
1024 |
with sub_header[1]:
|
1025 |
st.metric(
|
1026 |
label=target,
|
1027 |
+
value=format_numbers_f(
|
1028 |
float(_scenario.actual_total_sales)
|
1029 |
),
|
1030 |
)
|
|
|
1039 |
with sub_header[3]:
|
1040 |
st.metric(
|
1041 |
label=target,
|
1042 |
+
value=format_numbers_f(
|
1043 |
float(_scenario.modified_total_sales)
|
1044 |
),
|
1045 |
delta=numerize(_scenario.delta_sales, 1),
|
|
|
1085 |
st.button(
|
1086 |
"Reset",
|
1087 |
on_click=reset_scenario,
|
1088 |
+
args=(panel_selected, file_selected, updated_rcs),
|
1089 |
+
# use_container_width=True,
|
1090 |
)
|
1091 |
+
# st.write(target)
|
1092 |
+
|
1093 |
|
1094 |
_columns2 = st.columns((2, 2, 2))
|
1095 |
if st.session_state["optimization_key"] == "Media Spends":
|
|
|
1125 |
# key="total_spends_change_abs_slider",
|
1126 |
# on_change=update_all_spends_abs_slider,
|
1127 |
# )
|
1128 |
+
|
1129 |
elif st.session_state["optimization_key"] == target:
|
1130 |
+
# st.write(target)
|
1131 |
with _columns2[0]:
|
1132 |
sales_input = st.text_input(
|
1133 |
"Absolute",
|
|
|
1147 |
with _columns2[2]:
|
1148 |
min_value = round(_scenario.actual_total_sales * 0.5)
|
1149 |
max_value = round(_scenario.actual_total_sales * 1.5)
|
1150 |
+
st.write(min_value)
|
1151 |
+
st.write(max_value)
|
1152 |
+
# for value in range(min_value, max_value + 1, int(100)):
|
1153 |
+
# st.write(numerize(value, 1))
|
1154 |
st.session_state["total_sales_change_abs_slider_options"] = [
|
1155 |
numerize(value, 1)
|
1156 |
+
for value in range(min_value, max_value + 1, int(100))
|
1157 |
]
|
1158 |
|
1159 |
st.select_slider(
|
|
|
1161 |
options=st.session_state["total_sales_change_abs_slider_options"],
|
1162 |
key="total_sales_change_abs_slider",
|
1163 |
on_change=update_sales_abs_slider,
|
1164 |
+
# value=numerize(min_value, 1)
|
1165 |
)
|
1166 |
|
1167 |
if (
|
|
|
1186 |
"Optimize",
|
1187 |
on_click=optimize,
|
1188 |
args=(st.session_state["optimization_key"], status_placeholder),
|
1189 |
+
# use_container_width=True,
|
1190 |
)
|
1191 |
|
1192 |
st.markdown("""<hr class="spends-heading-seperator">""", unsafe_allow_html=True)
|
|
|
1214 |
"Old_sales":[]
|
1215 |
}
|
1216 |
for i, channel_name in enumerate(channels_list):
|
1217 |
+
# st.write(channel_name)
|
1218 |
_channel_class = st.session_state["scenario"].channels[channel_name]
|
1219 |
_columns = st.columns((2.5, 1.5, 1.5, 1.5, 1))
|
1220 |
with _columns[0]:
|
|
|
1286 |
|
1287 |
st.metric(
|
1288 |
target,
|
1289 |
+
format_numbers_f(current_channel_sales),
|
1290 |
delta=numerize(sales_delta, 1),
|
1291 |
label_visibility="collapsed",
|
1292 |
)
|
|
|
1319 |
col = channels_list[i]
|
1320 |
x_actual = st.session_state["scenario"].channels[col].actual_spends
|
1321 |
x_modified = st.session_state["scenario"].channels[col].modified_spends
|
1322 |
+
# x_modified_total = 0
|
1323 |
+
# for c in channels_list:
|
1324 |
+
# # st.write(c)
|
1325 |
+
# # st.write(st.session_state["scenario"].channels[c].modified_spends)
|
1326 |
+
# x_modified_total = x_modified_total + st.session_state["scenario"].channels[c].modified_spends.sum()
|
1327 |
+
# st.write(x_modified_total)
|
1328 |
+
|
1329 |
x_total = x_modified.sum()
|
1330 |
power = np.ceil(np.log(x_actual.max()) / np.log(10)) - 3
|
1331 |
|
|
|
1370 |
)
|
1371 |
|
1372 |
roi = y / np.maximum(x, np.finfo(float).eps)
|
1373 |
+
# roi = (y/np.sum(y))/(x/np.sum(x))
|
1374 |
+
# st.write(x)
|
1375 |
+
# st.write(y)
|
1376 |
+
# st.write(roi)
|
1377 |
|
1378 |
+
# st.write(roi[-1])
|
1379 |
+
|
1380 |
roi_current, marginal_roi_current = roi[-1], marginal_roi[-1]
|
1381 |
x, y, roi, marginal_roi = (
|
1382 |
x[:-1],
|
|
|
1385 |
marginal_roi[:-1],
|
1386 |
) # Drop data for current spends
|
1387 |
|
1388 |
+
# roi_current =
|
1389 |
+
|
1390 |
start_value, end_value, left_value, right_value = find_segment_value(
|
1391 |
x,
|
1392 |
roi,
|
|
|
1403 |
current_channel_spends,
|
1404 |
)
|
1405 |
|
1406 |
+
summary_df = pd.DataFrame(st.session_state["acutual_predicted"])
|
1407 |
+
# st.dataframe(summary_df)
|
1408 |
+
summary_df.drop_duplicates(subset="Channel_name", keep="last", inplace=True)
|
1409 |
+
# st.dataframe(summary_df)
|
1410 |
+
|
1411 |
+
summary_df_sorted = summary_df.sort_values(by="Delta", ascending=False)
|
1412 |
+
summary_df_sorted["Delta_percent"] = np.round(
|
1413 |
+
((summary_df_sorted["Optimized_spend"] / summary_df_sorted["Actual_spend"]) - 1)
|
1414 |
+
* 100,
|
1415 |
+
2,
|
1416 |
+
)
|
1417 |
+
|
1418 |
+
summary_df_sorted=summary_df_sorted.sort_values(by=['Optimized_spend'],ascending=False)
|
1419 |
+
summary_df_sorted['old_efficiency']=(summary_df_sorted['Old_sales']/summary_df_sorted['Old_sales'].sum())/(summary_df_sorted['Actual_spend']/summary_df_sorted['Actual_spend'].sum())
|
1420 |
+
summary_df_sorted['new_efficiency']=(summary_df_sorted['New_sales']/summary_df_sorted['New_sales'].sum())/(summary_df_sorted['Optimized_spend']/summary_df_sorted['Optimized_spend'].sum())
|
1421 |
+
|
1422 |
+
a = (summary_df_sorted[summary_df_sorted['Channel_name']== col]).reset_index()['new_efficiency'][0]
|
1423 |
+
# st.write(a)
|
1424 |
+
|
1425 |
with bin_placeholder:
|
1426 |
st.markdown(
|
1427 |
f"""
|
|
|
1432 |
text-align: center;
|
1433 |
color: #006EC0;
|
1434 |
">
|
1435 |
+
<p style="margin: 0; font-size: 20px;">Efficiency: {round(a,2)}</p>
|
1436 |
+
<!--<p style="margin: 0; font-size: 20px;">Marginal ROI: {round(marginal_roi_current,1)}</p>-->
|
1437 |
</div>
|
1438 |
""",
|
1439 |
unsafe_allow_html=True,
|
1440 |
)
|
1441 |
|
1442 |
+
with st.expander("See Response Curves", expanded=True):
|
1443 |
+
fig = plot_response_curves(summary_df_sorted)
|
1444 |
+
# st.plotly_chart(rc.response_curves(col))
|
1445 |
+
# st.plotly_chart(fig, use_container_width=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1446 |
|
1447 |
+
summary_df = pd.DataFrame(st.session_state["acutual_predicted"])
|
1448 |
+
# st.dataframe(summary_df)
|
1449 |
+
summary_df.drop_duplicates(subset="Channel_name", keep="last", inplace=True)
|
1450 |
+
# st.dataframe(summary_df)
|
1451 |
|
1452 |
+
summary_df_sorted = summary_df.sort_values(by="Delta", ascending=False)
|
1453 |
+
summary_df_sorted["Delta_percent"] = np.round(
|
1454 |
+
((summary_df_sorted["Optimized_spend"] / summary_df_sorted["Actual_spend"]) - 1)
|
1455 |
+
* 100,
|
1456 |
+
2,
|
1457 |
+
)
|
1458 |
+
|
1459 |
+
|
1460 |
+
|
1461 |
+
|
1462 |
|
1463 |
with open("summary_df.pkl", "wb") as f:
|
1464 |
pickle.dump(summary_df_sorted, f)
|
|
|
1474 |
# fig=summary_plot(summary_df_sorted, x='Optimized_spend', y='Channel_name', title='Planned Spend', text_column='Optimized_spend')
|
1475 |
# st.plotly_chart(fig,use_container_width=True)
|
1476 |
|
1477 |
+
scenario_planner_plots()
|
1478 |
+
|
1479 |
+
_columns = st.columns(2)
|
1480 |
+
# with _columns[0]:
|
1481 |
+
st.subheader("Save Scenario")
|
1482 |
+
scenario_name = st.text_input(
|
1483 |
+
"Scenario name",
|
1484 |
+
key="scenario_input",
|
1485 |
+
placeholder="Scenario name",
|
1486 |
+
label_visibility="collapsed",
|
1487 |
+
)
|
1488 |
+
st.button(
|
1489 |
+
"Save",
|
1490 |
+
on_click=lambda: save_scenario(scenario_name),
|
1491 |
+
disabled=len(st.session_state["scenario_input"]) == 0,#use_container_width=True
|
1492 |
+
)
|
1493 |
+
|
1494 |
+
|
1495 |
|
1496 |
elif auth_status == False:
|
1497 |
st.error("Username/Password is incorrect")
|
summary_df.pkl
CHANGED
@@ -1,3 +1,3 @@
|
|
1 |
version https://git-lfs.github.com/spec/v1
|
2 |
-
oid sha256:
|
3 |
-
size
|
|
|
1 |
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:41027251e75b11465e5cec329b14a8e35d4791aa6fdbbc948a0f32b4c1acc286
|
3 |
+
size 1886
|
utilities.py
CHANGED
@@ -931,6 +931,11 @@ def format_numbers(value, n_decimals=1, include_indicator=True):
|
|
931 |
else:
|
932 |
return f"{numerize(value,n_decimals)}"
|
933 |
|
|
|
|
|
|
|
|
|
|
|
934 |
|
935 |
def decimal_formater(num_string, n_decimals=1):
|
936 |
parts = num_string.split(".")
|
|
|
931 |
else:
|
932 |
return f"{numerize(value,n_decimals)}"
|
933 |
|
934 |
+
def format_numbers_f(value, n_decimals=1, include_indicator=False):
|
935 |
+
if include_indicator:
|
936 |
+
return f"{CURRENCY_INDICATOR} {numerize(value,n_decimals)}"
|
937 |
+
else:
|
938 |
+
return f"{numerize(value,n_decimals)}"
|
939 |
|
940 |
def decimal_formater(num_string, n_decimals=1):
|
941 |
parts = num_string.split(".")
|
utilities_with_panel.py
CHANGED
@@ -82,15 +82,15 @@ def nav_page(page_name, timeout_secs=3):
|
|
82 |
# <img src="https://assets-global.website-files.com/64c8fffb0e95cbc525815b79/64df84637f83a891c1473c51_Vector%20(Stroke).svg ">
|
83 |
# </div>""", unsafe_allow_html=True)
|
84 |
|
85 |
-
path = os.path.dirname(__file__)
|
86 |
|
87 |
-
file_ = open(f"{path}/mastercard_logo.png", "rb")
|
88 |
|
89 |
-
contents = file_.read()
|
90 |
|
91 |
-
data_url = base64.b64encode(contents).decode("utf-8")
|
92 |
|
93 |
-
file_.close()
|
94 |
|
95 |
|
96 |
|
@@ -136,7 +136,7 @@ def load_local_css(file_name):
|
|
136 |
# </div>""", unsafe_allow_html=True)
|
137 |
path1 = os.path.dirname(__file__)
|
138 |
|
139 |
-
file_1 = open(f"
|
140 |
|
141 |
contents1 = file_1.read()
|
142 |
|
@@ -723,9 +723,9 @@ def create_channel_summary(scenario):
|
|
723 |
|
724 |
actual_summary_df = pd.DataFrame([summary_columns, actual_spends_rows, actual_sales_rows, actual_roi_rows]).T
|
725 |
|
726 |
-
actual_summary_df.columns = ['Channel', 'Spends', '
|
727 |
|
728 |
-
actual_summary_df['
|
729 |
|
730 |
return actual_summary_df
|
731 |
|
@@ -771,7 +771,7 @@ def create_contribution_pie(scenario):
|
|
771 |
light_purple = 'rgba(255, 191, 69, 0.7)'
|
772 |
|
773 |
colors_map = {col:color for col,color in zip(st.session_state['channels_list'],plotly.colors.n_colors(plotly.colors.hex_to_rgb('#BE6468'), plotly.colors.hex_to_rgb('#E7B8B7'),23))}
|
774 |
-
total_contribution_fig = make_subplots(rows=1, cols=2,subplot_titles=['Media Spends','
|
775 |
total_contribution_fig.add_trace(
|
776 |
go.Pie(labels=[channel_name_formating(channel_name) for channel_name in st.session_state['channels_list']] + ['Non Media'],
|
777 |
values= [round(scenario.channels[channel_name].actual_total_spends * scenario.channels[channel_name].conversion_rate,1) for channel_name in st.session_state['channels_list']] + [0],
|
@@ -893,7 +893,7 @@ def create_contribution_pie(scenario):
|
|
893 |
# return total_contribution_fig
|
894 |
|
895 |
def create_contribuion_stacked_plot(scenario):
|
896 |
-
weekly_contribution_fig = make_subplots(rows=1, cols=2, subplot_titles=['Spends', '
|
897 |
raw_df = st.session_state['raw_df']
|
898 |
df = raw_df.sort_values(by='Date')
|
899 |
x = df.Date
|
@@ -916,7 +916,7 @@ def create_contribuion_stacked_plot(scenario):
|
|
916 |
x=x,
|
917 |
y=scenario.channels[channel_name].actual_sales,
|
918 |
name=channel_name_formating(channel_name),
|
919 |
-
hovertemplate="Date:%{x}<br>
|
920 |
legendgroup=channel_name,
|
921 |
showlegend=False,
|
922 |
marker_color=color,
|
@@ -931,7 +931,7 @@ def create_contribuion_stacked_plot(scenario):
|
|
931 |
x=x,
|
932 |
y=scenario.constant + scenario.correction,
|
933 |
name='Non Media',
|
934 |
-
hovertemplate="Date:%{x}<br>
|
935 |
marker_color=color_palette[-1],
|
936 |
), row=1, col=2)
|
937 |
|
@@ -950,8 +950,8 @@ def create_channel_spends_sales_plot(channel):
|
|
950 |
x=x,
|
951 |
y=_sales,
|
952 |
marker_color=color_palette[1], # You can choose a color from the palette
|
953 |
-
name='
|
954 |
-
hovertemplate="Date:%{x}<br>
|
955 |
), secondary_y=False)
|
956 |
|
957 |
channel_sales_spends_fig.add_trace(go.Scatter(
|
@@ -962,7 +962,7 @@ def create_channel_spends_sales_plot(channel):
|
|
962 |
hovertemplate="Date:%{x}<br>Spend:%{y:$.2s}",
|
963 |
), secondary_y=True)
|
964 |
|
965 |
-
channel_sales_spends_fig.update_layout(xaxis_title='Date', yaxis_title='
|
966 |
channel_sales_spends_fig.update_xaxes(showgrid=False)
|
967 |
channel_sales_spends_fig.update_yaxes(showgrid=False)
|
968 |
else:
|
@@ -976,11 +976,11 @@ def create_channel_spends_sales_plot(channel):
|
|
976 |
x=x,
|
977 |
y=_sales,
|
978 |
marker_color=color_palette[0], # You can choose a color from the palette
|
979 |
-
name='
|
980 |
-
hovertemplate="Date:%{x}<br>
|
981 |
), secondary_y=False)
|
982 |
|
983 |
-
channel_sales_spends_fig.update_layout(xaxis_title='Date', yaxis_title='
|
984 |
channel_sales_spends_fig.update_xaxes(showgrid=False)
|
985 |
channel_sales_spends_fig.update_yaxes(showgrid=False)
|
986 |
|
|
|
82 |
# <img src="https://assets-global.website-files.com/64c8fffb0e95cbc525815b79/64df84637f83a891c1473c51_Vector%20(Stroke).svg ">
|
83 |
# </div>""", unsafe_allow_html=True)
|
84 |
|
85 |
+
# path = os.path.dirname(__file__)
|
86 |
|
87 |
+
# file_ = open(f"{path}/mastercard_logo.png", "rb")
|
88 |
|
89 |
+
# contents = file_.read()
|
90 |
|
91 |
+
# data_url = base64.b64encode(contents).decode("utf-8")
|
92 |
|
93 |
+
# file_.close()
|
94 |
|
95 |
|
96 |
|
|
|
136 |
# </div>""", unsafe_allow_html=True)
|
137 |
path1 = os.path.dirname(__file__)
|
138 |
|
139 |
+
file_1 = open(f"ALDI_2017.png", "rb")
|
140 |
|
141 |
contents1 = file_1.read()
|
142 |
|
|
|
723 |
|
724 |
actual_summary_df = pd.DataFrame([summary_columns, actual_spends_rows, actual_sales_rows, actual_roi_rows]).T
|
725 |
|
726 |
+
actual_summary_df.columns = ['Channel', 'Spends', 'Prospects', 'ROI']
|
727 |
|
728 |
+
actual_summary_df['Prospects'] = actual_summary_df['Prospects'].map(lambda x: str(x)[1:])
|
729 |
|
730 |
return actual_summary_df
|
731 |
|
|
|
771 |
light_purple = 'rgba(255, 191, 69, 0.7)'
|
772 |
|
773 |
colors_map = {col:color for col,color in zip(st.session_state['channels_list'],plotly.colors.n_colors(plotly.colors.hex_to_rgb('#BE6468'), plotly.colors.hex_to_rgb('#E7B8B7'),23))}
|
774 |
+
total_contribution_fig = make_subplots(rows=1, cols=2,subplot_titles=['Media Spends','Prospects Contribution'],specs=[[{"type": "pie"}, {"type": "pie"}]])
|
775 |
total_contribution_fig.add_trace(
|
776 |
go.Pie(labels=[channel_name_formating(channel_name) for channel_name in st.session_state['channels_list']] + ['Non Media'],
|
777 |
values= [round(scenario.channels[channel_name].actual_total_spends * scenario.channels[channel_name].conversion_rate,1) for channel_name in st.session_state['channels_list']] + [0],
|
|
|
893 |
# return total_contribution_fig
|
894 |
|
895 |
def create_contribuion_stacked_plot(scenario):
|
896 |
+
weekly_contribution_fig = make_subplots(rows=1, cols=2, subplot_titles=['Spends', 'Prospects'], specs=[[{"type": "bar"}, {"type": "bar"}]])
|
897 |
raw_df = st.session_state['raw_df']
|
898 |
df = raw_df.sort_values(by='Date')
|
899 |
x = df.Date
|
|
|
916 |
x=x,
|
917 |
y=scenario.channels[channel_name].actual_sales,
|
918 |
name=channel_name_formating(channel_name),
|
919 |
+
hovertemplate="Date:%{x}<br>Prospects:%{y:$.2s}",
|
920 |
legendgroup=channel_name,
|
921 |
showlegend=False,
|
922 |
marker_color=color,
|
|
|
931 |
x=x,
|
932 |
y=scenario.constant + scenario.correction,
|
933 |
name='Non Media',
|
934 |
+
hovertemplate="Date:%{x}<br>Prospects:%{y:$.2s}",
|
935 |
marker_color=color_palette[-1],
|
936 |
), row=1, col=2)
|
937 |
|
|
|
950 |
x=x,
|
951 |
y=_sales,
|
952 |
marker_color=color_palette[1], # You can choose a color from the palette
|
953 |
+
name='Prospects',
|
954 |
+
hovertemplate="Date:%{x}<br>Prospects:%{y:$.2s}",
|
955 |
), secondary_y=False)
|
956 |
|
957 |
channel_sales_spends_fig.add_trace(go.Scatter(
|
|
|
962 |
hovertemplate="Date:%{x}<br>Spend:%{y:$.2s}",
|
963 |
), secondary_y=True)
|
964 |
|
965 |
+
channel_sales_spends_fig.update_layout(xaxis_title='Date', yaxis_title='Prospects', yaxis2_title='Spends ($)', title='Channel spends and Prospects week-wise')
|
966 |
channel_sales_spends_fig.update_xaxes(showgrid=False)
|
967 |
channel_sales_spends_fig.update_yaxes(showgrid=False)
|
968 |
else:
|
|
|
976 |
x=x,
|
977 |
y=_sales,
|
978 |
marker_color=color_palette[0], # You can choose a color from the palette
|
979 |
+
name='Prospects',
|
980 |
+
hovertemplate="Date:%{x}<br>Prospects:%{y:$.2s}",
|
981 |
), secondary_y=False)
|
982 |
|
983 |
+
channel_sales_spends_fig.update_layout(xaxis_title='Date', yaxis_title='Prospects', yaxis2_title='Spends ($)', title='Channel spends and Prospects week-wise')
|
984 |
channel_sales_spends_fig.update_xaxes(showgrid=False)
|
985 |
channel_sales_spends_fig.update_yaxes(showgrid=False)
|
986 |
|