Spaces:
Sleeping
Sleeping
Pragya Jatav
commited on
Commit
·
b12e77d
1
Parent(s):
bca631e
m1
Browse files- Model_Result_Overview.py +148 -279
- Overview_data_test_panel@#prospects.xlsx +0 -0
- Streamlit_functions.py +154 -1
- __pycache__/Streamlit_functions.cpython-310.pyc +0 -0
- __pycache__/classes.cpython-310.pyc +0 -0
- __pycache__/utilities.cpython-310.pyc +0 -0
- classes.py +73 -50
- pages/1_Model_Quality.py +1 -1
- pages/2_Scenario_Planner.py +4 -1
- pages/5_Glossary.py +17 -14
- response_curves_parameters.xlsx +0 -0
- summary_df.pkl +1 -1
- utilities.py +4 -3
Model_Result_Overview.py
CHANGED
|
@@ -107,287 +107,156 @@ if auth_status:
|
|
| 107 |
if not is_state_initiaized:
|
| 108 |
a=1
|
| 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 |
-
options = [
|
| 154 |
-
"Month on Month",
|
| 155 |
-
"Year on Year"]
|
| 156 |
-
col1, col2 = st.columns(2)
|
| 157 |
-
# Create a dropdown menu
|
| 158 |
-
with col1:
|
| 159 |
-
selected_option = st.selectbox('Select a comparison', options)
|
| 160 |
-
with col2:
|
| 161 |
-
st.markdown("""</br>""",unsafe_allow_html=True)
|
| 162 |
-
if selected_option == "Month on Month" :
|
| 163 |
-
|
| 164 |
-
st.markdown(
|
| 165 |
-
f"""
|
| 166 |
-
<div style="padding: 5px; border-radius: 5px; background-color: #FFFFE0; width: fit-content; display: inline-block;">
|
| 167 |
-
<strong> Comparision of current month spends to previous month spends</strong>
|
| 168 |
-
</div>
|
| 169 |
-
""",
|
| 170 |
-
unsafe_allow_html=True
|
| 171 |
-
)
|
| 172 |
-
else :
|
| 173 |
-
st.markdown(
|
| 174 |
-
f"""
|
| 175 |
-
<div style="padding: 5px; border-radius: 5px; background-color: #FFFFE0; width: fit-content; display: inline-block;">
|
| 176 |
-
<strong> Comparision of current month spends to the same month in previous year</strong>
|
| 177 |
-
</div>
|
| 178 |
-
""",
|
| 179 |
-
unsafe_allow_html=True
|
| 180 |
-
)
|
| 181 |
-
# Waterfall chart
|
| 182 |
-
|
| 183 |
-
def get_month_year_list(start_date, end_date):
|
| 184 |
-
# Generate a range of dates from start_date to end_date with a monthly frequency
|
| 185 |
-
dates = pd.date_range(start=start_date, end=end_date, freq='MS') # 'MS' is month start frequency
|
| 186 |
-
|
| 187 |
-
# Extract month and year from each date and create a list of tuples
|
| 188 |
-
month_year_list = [(date.month, date.year) for date in dates]
|
| 189 |
-
|
| 190 |
-
return month_year_list
|
| 191 |
-
def get_start_end_dates(month, year):
|
| 192 |
-
start_date = datetime(year, month, 1).date()
|
| 193 |
-
|
| 194 |
-
if month == 12:
|
| 195 |
-
end_date = datetime(year + 1, 1, 1).date() - timedelta(days=1)
|
| 196 |
-
else:
|
| 197 |
-
end_date = datetime(year, month + 1, 1).date() - timedelta(days=1)
|
| 198 |
-
|
| 199 |
-
return start_date, end_date
|
| 200 |
-
|
| 201 |
-
month_year_list = get_month_year_list(start_date, end_date)
|
| 202 |
-
dropdown_options = [f"{date.strftime('%B %Y')}" for date in pd.date_range(start=start_date, end=end_date, freq='MS')]
|
| 203 |
-
waterfall_option = st.selectbox("Select a month:", dropdown_options)
|
| 204 |
-
waterfall_date = datetime.strptime(waterfall_option, "%B %Y")
|
| 205 |
-
waterfall_month = waterfall_date.month
|
| 206 |
-
waterfall_year = waterfall_date.year
|
| 207 |
-
waterfall_start_date, waterfall_end_date = get_start_end_dates(waterfall_month, waterfall_year)
|
| 208 |
-
|
| 209 |
-
fig = sf.waterfall(waterfall_start_date,waterfall_end_date,selected_option)
|
| 210 |
-
st.plotly_chart(fig,use_container_width=True)
|
| 211 |
-
|
| 212 |
-
# Waterfall table
|
| 213 |
-
shares_df = sf.shares_df_func(waterfall_start_date,waterfall_end_date)
|
| 214 |
-
st.table(sf.waterfall_table_func(shares_df).style.format("{:.0%}"))
|
| 215 |
-
|
| 216 |
-
## Channel Contribution Bar Chart
|
| 217 |
-
st.plotly_chart(sf.channel_contribution(start_date,end_date),use_container_width=True)
|
| 218 |
-
st.plotly_chart(sf.chanel_spends(start_date,end_date),use_container_width=True)
|
| 219 |
-
# Format first three rows in percentage format
|
| 220 |
-
# styled_df = sf.shares_table_func(shares_df)
|
| 221 |
-
# # styled_df = styled_df.round(0).astype(int)
|
| 222 |
-
# styled_df.iloc[:3] = (styled_df.iloc[:3]).astype(int)
|
| 223 |
-
|
| 224 |
-
# # Round next two rows to two decimal places
|
| 225 |
-
# styled_df.iloc[3:5] = styled_df.iloc[3:5].round(0).astype(str)
|
| 226 |
-
|
| 227 |
-
# st.table(styled_df)
|
| 228 |
-
st.dataframe(sf.shares_table_func(shares_df),use_container_width=True)
|
| 229 |
-
|
| 230 |
-
st.dataframe(sf.eff_table_func(shares_df).style.format({"TOTAL SPEND": "{:,.0f}", "TOTAL SUPPORT": "{:,.0f}", "TOTAL CONTRIBUTION": "{:,.0f}"}),use_container_width=True)
|
| 231 |
-
|
| 232 |
-
### CPP CHART
|
| 233 |
-
st.plotly_chart(sf.cpp(start_date,end_date),use_container_width=True)
|
| 234 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 235 |
### Base decomp CHART
|
| 236 |
-
|
| 237 |
|
| 238 |
### Media decomp CHART
|
| 239 |
-
|
| 240 |
|
| 241 |
-
|
| 242 |
-
# st.write(fig.columns)
|
| 243 |
-
# st.dataframe(fig)
|
| 244 |
-
|
| 245 |
-
# def panel_fetch(file_selected):
|
| 246 |
-
# raw_data_mmm_df = pd.read_excel(file_selected, sheet_name="RAW DATA MMM")
|
| 247 |
-
|
| 248 |
-
# if "Panel" in raw_data_mmm_df.columns:
|
| 249 |
-
# panel = list(set(raw_data_mmm_df["Panel"]))
|
| 250 |
-
# else:
|
| 251 |
-
# raw_data_mmm_df = None
|
| 252 |
-
# panel = None
|
| 253 |
-
|
| 254 |
-
# return panel
|
| 255 |
-
|
| 256 |
-
# def rerun():
|
| 257 |
-
# st.rerun()
|
| 258 |
-
|
| 259 |
-
# metrics_selected='prospects'
|
| 260 |
-
|
| 261 |
-
# file_selected = (
|
| 262 |
-
# f"Overview_data_test_panel@#{metrics_selected}.xlsx"
|
| 263 |
-
# )
|
| 264 |
-
# panel_list = panel_fetch(file_selected)
|
| 265 |
-
|
| 266 |
-
# if "selected_markets" not in st.session_state:
|
| 267 |
-
# st.session_state['selected_markets']='DMA1'
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
# st.header('Overview of previous spends')
|
| 271 |
-
|
| 272 |
-
# selected_market= st.selectbox(
|
| 273 |
-
# "Select Markets",
|
| 274 |
-
# ["Total Market"] + panel_list
|
| 275 |
-
# )
|
| 276 |
-
|
| 277 |
-
|
| 278 |
-
|
| 279 |
-
# initialize_data(target_col,selected_market)
|
| 280 |
-
# scenario = st.session_state['scenario']
|
| 281 |
-
# raw_df = st.session_state['raw_df']
|
| 282 |
-
# st.write(scenario.actual_total_spends)
|
| 283 |
-
# st.write(scenario.actual_total_sales)
|
| 284 |
-
# columns = st.columns((1,1,3))
|
| 285 |
-
|
| 286 |
-
# with columns[0]:
|
| 287 |
-
# st.metric(label='Spends', value=format_numbers(float(scenario.actual_total_spends)))
|
| 288 |
-
# #### print(f"##################### {scenario.actual_total_sales} ##################")
|
| 289 |
-
# with columns[1]:
|
| 290 |
-
# st.metric(label=target, value=format_numbers(float(scenario.actual_total_sales),include_indicator=False))
|
| 291 |
-
|
| 292 |
-
|
| 293 |
-
# actual_summary_df = create_channel_summary(scenario)
|
| 294 |
-
# actual_summary_df['Channel'] = actual_summary_df['Channel'].apply(channel_name_formating)
|
| 295 |
-
|
| 296 |
-
# columns = st.columns((2,1))
|
| 297 |
-
# #with columns[0]:
|
| 298 |
-
# with st.expander('Channel wise overview'):
|
| 299 |
-
# st.markdown(actual_summary_df.style.set_table_styles(
|
| 300 |
-
# [{
|
| 301 |
-
# 'selector': 'th',
|
| 302 |
-
# 'props': [('background-color', '#FFFFF')]
|
| 303 |
-
# },
|
| 304 |
-
# {
|
| 305 |
-
# 'selector' : 'tr:nth-child(even)',
|
| 306 |
-
# 'props' : [('background-color', '#FFFFF')]
|
| 307 |
-
# }]).to_html(), unsafe_allow_html=True)
|
| 308 |
-
|
| 309 |
-
# st.markdown("<hr>",unsafe_allow_html=True)
|
| 310 |
-
# ##############################
|
| 311 |
-
|
| 312 |
-
# st.plotly_chart(create_contribution_pie(scenario),use_container_width=True)
|
| 313 |
-
# st.markdown("<hr>",unsafe_allow_html=True)
|
| 314 |
-
|
| 315 |
-
|
| 316 |
-
# ################################3
|
| 317 |
-
# st.plotly_chart(create_contribuion_stacked_plot(scenario),use_container_width=True)
|
| 318 |
-
# st.markdown("<hr>",unsafe_allow_html=True)
|
| 319 |
-
# #######################################
|
| 320 |
-
|
| 321 |
-
# selected_channel_name = st.selectbox('Channel', st.session_state['channels_list'] + ['non media'], format_func=channel_name_formating)
|
| 322 |
-
# selected_channel = scenario.channels.get(selected_channel_name,None)
|
| 323 |
-
|
| 324 |
-
# st.plotly_chart(create_channel_spends_sales_plot(selected_channel), use_container_width=True)
|
| 325 |
-
|
| 326 |
-
# st.markdown("<hr>",unsafe_allow_html=True)
|
| 327 |
-
|
| 328 |
-
# elif auth_status == False:
|
| 329 |
-
# st.error('Username/Password is incorrect')
|
| 330 |
-
|
| 331 |
-
# if auth_status != True:
|
| 332 |
-
# try:
|
| 333 |
-
# username_forgot_pw, email_forgot_password, random_password = authenticator.forgot_password('Forgot password')
|
| 334 |
-
# if username_forgot_pw:
|
| 335 |
-
# st.success('New password sent securely')
|
| 336 |
-
# # Random password to be transferred to user securely
|
| 337 |
-
# elif username_forgot_pw == False:
|
| 338 |
-
# st.error('Username not found')
|
| 339 |
-
# except Exception as e:
|
| 340 |
-
# st.error(e)
|
| 341 |
-
# st.header("")
|
| 342 |
-
# st.markdown("<h5 style='font-weight: normal;'>MMM Readout for Selected Period</h5>", unsafe_allow_html=True)
|
| 343 |
-
# #### Input Select Start and End Date
|
| 344 |
-
|
| 345 |
-
# # Create two columns for start date and end date input
|
| 346 |
-
# col1, col2 = st.columns(2)
|
| 347 |
-
|
| 348 |
-
# with col1:
|
| 349 |
-
# start_date = st.date_input("Start Date: ")
|
| 350 |
-
|
| 351 |
-
# with col2:
|
| 352 |
-
# end_date = st.date_input("End Date: ")
|
| 353 |
-
# # Dropdown menu options
|
| 354 |
-
# options = [
|
| 355 |
-
# "Month on Month",
|
| 356 |
-
# "Year on Year"]
|
| 357 |
-
# col1, col2 = st.columns(2)
|
| 358 |
-
# # Create a dropdown menu
|
| 359 |
-
# with col1:
|
| 360 |
-
# selected_option = st.selectbox('Select a comparison', options)
|
| 361 |
-
# with col2:
|
| 362 |
-
# st.write("")
|
| 363 |
-
# # Waterfall chart
|
| 364 |
-
# fig = sf.waterfall(start_date,end_date,selected_option)
|
| 365 |
-
# st.plotly_chart(fig)
|
| 366 |
-
|
| 367 |
-
# # Waterfall table
|
| 368 |
-
# shares_df = sf.shares_df_func(start_date,end_date)
|
| 369 |
-
# st.table(sf.waterfall_table_func(shares_df).style.format("{:.0%}"))
|
| 370 |
-
|
| 371 |
-
# ## Channel Contribution Bar Chart
|
| 372 |
-
# st.plotly_chart(sf.channel_contribution(start_date,end_date))
|
| 373 |
-
# # Format first three rows in percentage format
|
| 374 |
-
# # styled_df = sf.shares_table_func(shares_df)
|
| 375 |
-
# # # styled_df = styled_df.round(0).astype(int)
|
| 376 |
-
# # styled_df.iloc[:3] = (styled_df.iloc[:3]).astype(int)
|
| 377 |
-
|
| 378 |
-
# # # Round next two rows to two decimal places
|
| 379 |
-
# # styled_df.iloc[3:5] = styled_df.iloc[3:5].round(0).astype(str)
|
| 380 |
-
|
| 381 |
-
# # st.table(styled_df)
|
| 382 |
-
# st.dataframe(sf.shares_table_func(shares_df))
|
| 383 |
-
|
| 384 |
-
# st.dataframe(sf.eff_table_func(shares_df))
|
| 385 |
-
|
| 386 |
-
# ### CPP CHART
|
| 387 |
-
# st.plotly_chart(sf.cpp(start_date,end_date))
|
| 388 |
-
|
| 389 |
-
# ### Base decomp CHART
|
| 390 |
-
# st.plotly_chart(sf.base_decomp())
|
| 391 |
-
|
| 392 |
-
# ### Media decomp CHART
|
| 393 |
-
# st.plotly_chart(sf.media_decomp())
|
|
|
|
| 107 |
if not is_state_initiaized:
|
| 108 |
a=1
|
| 109 |
|
| 110 |
+
with st.expander("View Channel Wise Spend And Prospect Analysis "):
|
| 111 |
+
# Create two columns for start date and end date input
|
| 112 |
+
col1, col2 = st.columns(2)
|
| 113 |
+
min_date,max_date = sf.get_date_range()
|
| 114 |
+
# st.write(min_date,max_date)
|
| 115 |
+
# min_date = datetime(2023, 1, 1)
|
| 116 |
+
# max_date = datetime(2024, 12, 31)
|
| 117 |
+
default_date1,default_date2 = sf.get_default_dates()
|
| 118 |
+
# st.write(default_date1,default_date2)
|
| 119 |
+
with col1:
|
| 120 |
+
start_date = st.date_input("Start Date: ",value=default_date1,min_value=min_date,
|
| 121 |
+
max_value=max_date)
|
| 122 |
+
with col2:
|
| 123 |
+
end_date = st.date_input("End Date: ",value = default_date2,min_value=min_date,
|
| 124 |
+
max_value=max_date)
|
| 125 |
+
# col1, col2 = st.columns(2)
|
| 126 |
+
# with col1:
|
| 127 |
+
# fig = sf.pie_spend(start_date,end_date)
|
| 128 |
+
# st.plotly_chart(fig,use_container_width=True)
|
| 129 |
+
# with col2:
|
| 130 |
+
# fig = sf.pie_contributions(start_date,end_date)
|
| 131 |
+
# st.plotly_chart(fig,use_container_width=True)
|
| 132 |
+
# st.header("Distribution of Spends and Contributions")
|
| 133 |
+
fig = sf.pie_charts(start_date,end_date)
|
| 134 |
+
st.plotly_chart(fig,use_container_width=True)
|
| 135 |
+
|
| 136 |
+
## Channel Contribution Bar Chart
|
| 137 |
+
st.plotly_chart(sf.channel_contribution(start_date,end_date),use_container_width=True)
|
| 138 |
+
st.plotly_chart(sf.chanel_spends(start_date,end_date),use_container_width=True)
|
| 139 |
+
# Format first three rows in percentage format
|
| 140 |
+
# styled_df = sf.shares_table_func(shares_df)
|
| 141 |
+
# # styled_df = styled_df.round(0).astype(int)
|
| 142 |
+
# styled_df.iloc[:3] = (styled_df.iloc[:3]).astype(int)
|
| 143 |
+
|
| 144 |
+
# # Round next two rows to two decimal places
|
| 145 |
+
# styled_df.iloc[3:5] = styled_df.iloc[3:5].round(0).astype(str)
|
| 146 |
+
|
| 147 |
+
# st.table(styled_df)
|
| 148 |
+
shares_df = sf.shares_df_func(start_date,end_date)
|
| 149 |
+
st.dataframe(sf.shares_table_func(shares_df),use_container_width=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
|
| 151 |
+
st.dataframe(sf.eff_table_func(shares_df).style.format({"TOTAL SPEND": "{:,.0f}", "TOTAL SUPPORT": "{:,.0f}", "TOTAL CONTRIBUTION": "{:,.0f}"}),use_container_width=True)
|
| 152 |
+
|
| 153 |
+
### CPP CHART
|
| 154 |
+
st.plotly_chart(sf.cpp(start_date,end_date),use_container_width=True)
|
| 155 |
+
data_selection_type = st.radio("Select Input Type",["Compare Monthly Change", "Compare Custom Range"])
|
| 156 |
+
waterfall_start_date,waterfall_end_date = start_date,end_date
|
| 157 |
+
with st.expander("View Change in MMM Estimated Prospect Contributions Analysis"):
|
| 158 |
+
# Dropdown menu options
|
| 159 |
+
st.markdown("<h1 style='font-size:28px;'>Change in MMM Estimated Prospect Contributions</h1>", unsafe_allow_html=True)
|
| 160 |
+
if data_selection_type == "Compare Monthly Change":
|
| 161 |
+
options = [
|
| 162 |
+
"Month on Month",
|
| 163 |
+
"Year on Year"]
|
| 164 |
+
col1, col2 = st.columns(2)
|
| 165 |
+
# Create a dropdown menu
|
| 166 |
+
with col1:
|
| 167 |
+
selected_option = st.selectbox('Select a comparison', options)
|
| 168 |
+
with col2:
|
| 169 |
+
st.markdown("""</br>""",unsafe_allow_html=True)
|
| 170 |
+
if selected_option == "Month on Month" :
|
| 171 |
+
|
| 172 |
+
st.markdown(
|
| 173 |
+
f"""
|
| 174 |
+
<div style="padding: 5px; border-radius: 5px; background-color: #FFFFE0; width: fit-content; display: inline-block;">
|
| 175 |
+
<strong> Comparision of current month spends to previous month spends</strong>
|
| 176 |
+
</div>
|
| 177 |
+
""",
|
| 178 |
+
unsafe_allow_html=True
|
| 179 |
+
)
|
| 180 |
+
else :
|
| 181 |
+
st.markdown(
|
| 182 |
+
f"""
|
| 183 |
+
<div style="padding: 5px; border-radius: 5px; background-color: #FFFFE0; width: fit-content; display: inline-block;">
|
| 184 |
+
<strong> Comparision of current month spends to the same month in previous year</strong>
|
| 185 |
+
</div>
|
| 186 |
+
""",
|
| 187 |
+
unsafe_allow_html=True
|
| 188 |
+
)
|
| 189 |
+
# Waterfall chart
|
| 190 |
+
|
| 191 |
+
def get_month_year_list(start_date, end_date):
|
| 192 |
+
# Generate a range of dates from start_date to end_date with a monthly frequency
|
| 193 |
+
dates = pd.date_range(start=start_date, end=end_date, freq='MS') # 'MS' is month start frequency
|
| 194 |
+
|
| 195 |
+
# Extract month and year from each date and create a list of tuples
|
| 196 |
+
month_year_list = [(date.month, date.year) for date in dates]
|
| 197 |
+
|
| 198 |
+
return month_year_list
|
| 199 |
+
def get_start_end_dates(month, year):
|
| 200 |
+
start_date = datetime(year, month, 1).date()
|
| 201 |
+
|
| 202 |
+
if month == 12:
|
| 203 |
+
end_date = datetime(year + 1, 1, 1).date() - timedelta(days=1)
|
| 204 |
+
else:
|
| 205 |
+
end_date = datetime(year, month + 1, 1).date() - timedelta(days=1)
|
| 206 |
+
|
| 207 |
+
return start_date, end_date
|
| 208 |
+
|
| 209 |
+
month_year_list = get_month_year_list(start_date, end_date)
|
| 210 |
+
dropdown_options = [f"{date.strftime('%B %Y')}" for date in pd.date_range(start=start_date, end=end_date, freq='MS')]
|
| 211 |
+
waterfall_option = st.selectbox("Select a month:", dropdown_options)
|
| 212 |
+
waterfall_date = datetime.strptime(waterfall_option, "%B %Y")
|
| 213 |
+
waterfall_month = waterfall_date.month
|
| 214 |
+
waterfall_year = waterfall_date.year
|
| 215 |
+
waterfall_start_date, waterfall_end_date = get_start_end_dates(waterfall_month, waterfall_year)
|
| 216 |
+
# st.write("abc")
|
| 217 |
+
# figw = sf.waterfall(waterfall_start_date,waterfall_end_date)
|
| 218 |
+
figw= sf.waterfall(waterfall_start_date,waterfall_end_date,selected_option)
|
| 219 |
+
st.plotly_chart(figw,use_container_width=True)
|
| 220 |
+
|
| 221 |
+
elif data_selection_type == "Compare Custom Range":
|
| 222 |
+
col1, col2 = st.columns(2)
|
| 223 |
+
min_date,max_date = sf.get_date_range()
|
| 224 |
+
with col1:
|
| 225 |
+
st.write("Select Time Period 1")
|
| 226 |
+
sc1,sc2 = st.columns(2)
|
| 227 |
+
with sc1:
|
| 228 |
+
waterfall_start_date1 = st.date_input("Start Date 1: ",value=start_date,min_value=min_date,
|
| 229 |
+
max_value=max_date)
|
| 230 |
+
with sc2:
|
| 231 |
+
waterfall_end_date1 = st.date_input("End Date 1: ",value = end_date,min_value=min_date,
|
| 232 |
+
max_value=max_date)
|
| 233 |
+
with col2:
|
| 234 |
+
st.write("Select Time Period 2")
|
| 235 |
+
ec1,ec2 = st.columns(2)
|
| 236 |
+
with ec1:
|
| 237 |
+
waterfall_start_date2 = st.date_input("Start Date 2: ",value=end_date-timedelta(days = -1),min_value=min_date,
|
| 238 |
+
max_value=max_date)
|
| 239 |
+
with ec2:
|
| 240 |
+
diff = min((start_date-end_date).days,-30)
|
| 241 |
+
waterfall_end_date2 = st.date_input("End Date 2: ",value = start_date,min_value=min_date,
|
| 242 |
+
max_value=max_date)
|
| 243 |
+
try:
|
| 244 |
+
figw= sf.waterfall2(waterfall_start_date1,waterfall_end_date1,waterfall_start_date2,waterfall_end_date2)
|
| 245 |
+
st.plotly_chart(figw,use_container_width=True)
|
| 246 |
+
except:
|
| 247 |
+
st.warning("Previous data does not exist")
|
| 248 |
+
|
| 249 |
+
|
| 250 |
+
|
| 251 |
+
# Waterfall table
|
| 252 |
+
# shares_df = sf.shares_df_func(waterfall_start_date,waterfall_end_date)
|
| 253 |
+
st.table(sf.waterfall_table_func(shares_df).style.format("{:.0%}"))
|
| 254 |
+
|
| 255 |
+
|
| 256 |
+
with st.expander("View Decomposition Analysis"):
|
| 257 |
### Base decomp CHART
|
| 258 |
+
st.plotly_chart(sf.base_decomp(),use_container_width=True)
|
| 259 |
|
| 260 |
### Media decomp CHART
|
| 261 |
+
st.plotly_chart(sf.media_decomp(),use_container_width=True)
|
| 262 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Overview_data_test_panel@#prospects.xlsx
CHANGED
|
Binary files a/Overview_data_test_panel@#prospects.xlsx and b/Overview_data_test_panel@#prospects.xlsx differ
|
|
|
Streamlit_functions.py
CHANGED
|
@@ -254,7 +254,160 @@ def pie_contributions(start_date,end_date):
|
|
| 254 |
|
| 255 |
# Show the figure
|
| 256 |
return fig
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 257 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 258 |
def waterfall(start_date,end_date,btn_chart):
|
| 259 |
# if pd.isnull(start_date) == True :
|
| 260 |
# start_date = datetime(2024, 1, 28)
|
|
@@ -1314,7 +1467,7 @@ def scenario_spend_forecasting2(delta_df,start_date,end_date):
|
|
| 1314 |
return "Invalid month number"
|
| 1315 |
|
| 1316 |
data2["Month year"] = data2["Month"].apply(get_month_name) + ' ' +(data2["Date"].dt.year+1).astype(str)
|
| 1317 |
-
print(data2.columns)
|
| 1318 |
data2 = data2[['Month year' ,'BROADCAST TV', 'CABLE TV',
|
| 1319 |
'CONNECTED & OTT TV', 'VIDEO', 'DISPLAY PROSPECTING',
|
| 1320 |
'DISPLAY RETARGETING', 'SOCIAL PROSPECTING', 'SOCIAL RETARGETING',
|
|
|
|
| 254 |
|
| 255 |
# Show the figure
|
| 256 |
return fig
|
| 257 |
+
def waterfall2(start_date1,end_date1,start_date2,end_date2):
|
| 258 |
+
btn_chart = "Month on Month"
|
| 259 |
+
# if pd.isnull(start_date) == True :
|
| 260 |
+
# start_date = datetime(2024, 1, 28)
|
| 261 |
+
# if pd.isnull(end_date) == True :
|
| 262 |
+
# end_date = datetime(2024, 2, 24)
|
| 263 |
+
# start_date = datetime.strptime(start_date, "%Y-%m-%d")
|
| 264 |
+
# end_date = datetime.strptime(end_date, "%Y-%m-%d")
|
| 265 |
+
# start_date = start_date.datetime.data
|
| 266 |
+
# end_date = end_date.datetime.data
|
| 267 |
+
start_date1 = pd.to_datetime(start_date1)
|
| 268 |
+
end_date1 = pd.to_datetime(end_date1)
|
| 269 |
+
start_date2 = pd.to_datetime(start_date2)
|
| 270 |
+
end_date2 = pd.to_datetime(end_date2)
|
| 271 |
+
|
| 272 |
+
# if btn_chart == "Month on Month":
|
| 273 |
+
# start_date_prev = start_date +timedelta(weeks=-4)
|
| 274 |
+
# end_date_prev = start_date +timedelta(days=-1)
|
| 275 |
+
# else:
|
| 276 |
+
# start_date_prev = start_date +timedelta(weeks=-52)
|
| 277 |
+
# end_date_prev = start_date_prev +timedelta(weeks=4) +timedelta(days=-1)
|
| 278 |
+
|
| 279 |
+
|
| 280 |
+
if start_date1 < df['Date'].min() :
|
| 281 |
+
return "a"
|
| 282 |
+
|
| 283 |
+
cur_data = df[(df['Date'] >= start_date2) & (df['Date'] <= end_date2)]
|
| 284 |
+
prev_data = df[(df['Date'] >= start_date1) & (df['Date'] <= end_date1)]
|
| 285 |
+
|
| 286 |
+
|
| 287 |
+
# Example data for the waterfall chart
|
| 288 |
+
data = [
|
| 289 |
+
{'label': 'Previous Period', 'value': round(prev_data[contribution_cols].values.sum())},
|
| 290 |
+
{'label': 'Broadcast TV', 'value': round(cur_data['Broadcast TV_Prospects'].sum()-prev_data['Broadcast TV_Prospects'].sum())},
|
| 291 |
+
{'label': 'Cable TV', 'value': round(cur_data['Cable TV_Prospects'].sum()-prev_data['Cable TV_Prospects'].sum())},
|
| 292 |
+
{'label': 'Connected & OTT TV', 'value': round(cur_data['Connected & OTT TV_Prospects'].sum()-prev_data['Connected & OTT TV_Prospects'].sum())},
|
| 293 |
+
{'label': 'Video', 'value': round(cur_data['Video_Prospects'].sum()-prev_data['Video_Prospects'].sum())},
|
| 294 |
+
{'label': 'Display Prospecting', 'value': round(cur_data['Display Prospecting_Prospects'].sum()-prev_data['Display Prospecting_Prospects'].sum())},
|
| 295 |
+
{'label': 'Display Retargeting', 'value': round(cur_data['Display Retargeting_Prospects'].sum()-prev_data['Display Retargeting_Prospects'].sum())},
|
| 296 |
+
{'label': 'Social Prospecting', 'value': round(cur_data['Social Prospecting_Prospects'].sum()-prev_data['Social Prospecting_Prospects'].sum())},
|
| 297 |
+
{'label': 'Social Retargeting', 'value': round(cur_data['Social Retargeting_Prospects'].sum()-prev_data['Social Retargeting_Prospects'].sum())},
|
| 298 |
+
{'label': 'Search Brand', 'value': round(cur_data['Search Brand_Prospects'].sum()-prev_data['Search Brand_Prospects'].sum())},
|
| 299 |
+
{'label': 'Search Non-brand', 'value': round(cur_data['Search Non-brand_Prospects'].sum()-prev_data['Search Non-brand_Prospects'].sum())},
|
| 300 |
+
{'label': 'Digital Partners', 'value': round(cur_data['Digital Partners_Prospects'].sum()-prev_data['Digital Partners_Prospects'].sum())},
|
| 301 |
+
{'label': 'Audio', 'value': round(cur_data['Audio_Prospects'].sum()-prev_data['Audio_Prospects'].sum())},
|
| 302 |
+
{'label': 'Email', 'value': round(cur_data['Email_Prospects'].sum()-prev_data['Email_Prospects'].sum())},
|
| 303 |
+
{'label': 'Current Period', 'value': round(cur_data[contribution_cols].values.sum())}
|
| 304 |
+
]
|
| 305 |
+
|
| 306 |
+
# Calculate cumulative values for the waterfall chart
|
| 307 |
+
cumulative = [0]
|
| 308 |
+
for i in range(len(data)):
|
| 309 |
+
cumulative.append(cumulative[-1] + data[i]['value'])
|
| 310 |
+
|
| 311 |
+
# Adjusting values to start from zero for both first and last columns
|
| 312 |
+
cumulative[-1] = 0 # Set the last cumulative value to zero
|
| 313 |
+
|
| 314 |
+
# Extracting labels and values
|
| 315 |
+
labels = [item['label'] for item in data]
|
| 316 |
+
values = [item['value'] for item in data]
|
| 317 |
+
|
| 318 |
+
# Plotting the waterfall chart using go.Bar
|
| 319 |
+
bars = []
|
| 320 |
+
for i in range(len(data)):
|
| 321 |
+
color = '#4A88D9' if i == 0 or i == len(data) - 1 else '#DC5537' # Blue for first and last, gray for others
|
| 322 |
+
hover_text = f"<b>{labels[i]}</b><br>Value: {abs(values[i])}"
|
| 323 |
+
|
| 324 |
+
bars.append(go.Bar(
|
| 325 |
+
x=[labels[i]],
|
| 326 |
+
y=[cumulative[i+1] - cumulative[i]],
|
| 327 |
+
base=[cumulative[i]],
|
| 328 |
+
text=[f"{abs(values[i]):,}"],
|
| 329 |
+
textposition='auto',
|
| 330 |
+
hovertemplate=hover_text,
|
| 331 |
+
marker=dict(color=color),
|
| 332 |
+
showlegend=False
|
| 333 |
+
))
|
| 334 |
|
| 335 |
+
# Creating the figure
|
| 336 |
+
fig = go.Figure(data=bars)
|
| 337 |
+
|
| 338 |
+
# Updating layout for black background and gray gridlines
|
| 339 |
+
if btn_chart == "Month on Month":
|
| 340 |
+
fig.update_layout(
|
| 341 |
+
title=f"Change In MMM Estimated Prospect Contribution"
|
| 342 |
+
,showlegend=False,
|
| 343 |
+
# plot_bgcolor='black',
|
| 344 |
+
# paper_bgcolor='black',
|
| 345 |
+
# font=dict(color='white'), # Changing font color to white for better contrast
|
| 346 |
+
xaxis=dict(
|
| 347 |
+
showgrid=False,
|
| 348 |
+
zeroline=False, # Hiding the x-axis zero line
|
| 349 |
+
),
|
| 350 |
+
yaxis=dict(
|
| 351 |
+
title="Prospects",
|
| 352 |
+
showgrid=True,
|
| 353 |
+
gridcolor='lightgray',
|
| 354 |
+
griddash='dot', # Setting y-axis gridline color to gray
|
| 355 |
+
zeroline=False, # Hiding the y-axis zero line
|
| 356 |
+
# range=[18000, max(max(cumulative), max(values)) + 1000] # Setting the y-axis range from 19k to slightly above the maximum value
|
| 357 |
+
)
|
| 358 |
+
)
|
| 359 |
+
fig.add_annotation(
|
| 360 |
+
text=f"{start_date2.strftime('%m-%d-%Y')} to {end_date2.strftime('%m-%d-%Y')} vs. {start_date1.strftime('%m-%d-%Y')} To {end_date1.strftime('%m-%d-%Y')}",
|
| 361 |
+
x=0,
|
| 362 |
+
y=1.15,
|
| 363 |
+
xref="x domain",
|
| 364 |
+
yref="y domain",
|
| 365 |
+
showarrow=False,
|
| 366 |
+
font=dict(size=16),
|
| 367 |
+
# align='left'
|
| 368 |
+
)
|
| 369 |
+
# fig.update_xaxes(
|
| 370 |
+
# tickmode="array",
|
| 371 |
+
# # categoryorder="total ascending",
|
| 372 |
+
# tickvals=[f"{abs(values[i])}"],
|
| 373 |
+
# ticktext=[f"{abs(values[i])}"],
|
| 374 |
+
# ticklabelposition="outside",
|
| 375 |
+
# tickfont=dict(color="white"),
|
| 376 |
+
# )
|
| 377 |
+
else :
|
| 378 |
+
fig.update_layout(
|
| 379 |
+
showlegend=False,
|
| 380 |
+
# plot_bgcolor='black',
|
| 381 |
+
# paper_bgcolor='black',
|
| 382 |
+
# font=dict(color='white'), # Changing font color to white for better contrast
|
| 383 |
+
xaxis=dict(
|
| 384 |
+
showgrid=False,
|
| 385 |
+
zeroline=False, # Hiding the x-axis zero line
|
| 386 |
+
),
|
| 387 |
+
yaxis=dict(
|
| 388 |
+
title="Prospects",
|
| 389 |
+
showgrid=True,
|
| 390 |
+
gridcolor='lightgray',
|
| 391 |
+
griddash='dot', # Setting y-axis gridline color to gray
|
| 392 |
+
zeroline=False, # Hiding the y-axis zero line
|
| 393 |
+
# range=[10000, max(cumulative)+1000] # Setting the y-axis range from 19k to slightly above the maximum value
|
| 394 |
+
)
|
| 395 |
+
|
| 396 |
+
)
|
| 397 |
+
fig.add_annotation(
|
| 398 |
+
text=f"{start_date_prev.strftime('%m-%d-%Y')} to {end_date_prev.strftime('%m-%d-%Y')} vs. {start_date.strftime('%m-%d-%Y')} To {end_date.strftime('%m-%d-%Y')}",
|
| 399 |
+
x=0,
|
| 400 |
+
y=1.15,
|
| 401 |
+
xref="x domain",
|
| 402 |
+
yref="y domain",
|
| 403 |
+
showarrow=False,
|
| 404 |
+
font=dict(size=16),
|
| 405 |
+
# align='left'
|
| 406 |
+
)
|
| 407 |
+
# # print(cur_data)
|
| 408 |
+
# # print(prev_data)
|
| 409 |
+
# fig.show()
|
| 410 |
+
return fig
|
| 411 |
def waterfall(start_date,end_date,btn_chart):
|
| 412 |
# if pd.isnull(start_date) == True :
|
| 413 |
# start_date = datetime(2024, 1, 28)
|
|
|
|
| 1467 |
return "Invalid month number"
|
| 1468 |
|
| 1469 |
data2["Month year"] = data2["Month"].apply(get_month_name) + ' ' +(data2["Date"].dt.year+1).astype(str)
|
| 1470 |
+
# print(data2.columns)
|
| 1471 |
data2 = data2[['Month year' ,'BROADCAST TV', 'CABLE TV',
|
| 1472 |
'CONNECTED & OTT TV', 'VIDEO', 'DISPLAY PROSPECTING',
|
| 1473 |
'DISPLAY RETARGETING', 'SOCIAL PROSPECTING', 'SOCIAL RETARGETING',
|
__pycache__/Streamlit_functions.cpython-310.pyc
CHANGED
|
Binary files a/__pycache__/Streamlit_functions.cpython-310.pyc and b/__pycache__/Streamlit_functions.cpython-310.pyc differ
|
|
|
__pycache__/classes.cpython-310.pyc
CHANGED
|
Binary files a/__pycache__/classes.cpython-310.pyc and b/__pycache__/classes.cpython-310.pyc differ
|
|
|
__pycache__/utilities.cpython-310.pyc
CHANGED
|
Binary files a/__pycache__/utilities.cpython-310.pyc and b/__pycache__/utilities.cpython-310.pyc differ
|
|
|
classes.py
CHANGED
|
@@ -100,7 +100,7 @@ class Channel:
|
|
| 100 |
self.modified_total_sales = self.modified_sales.sum()
|
| 101 |
self.delta_spends = self.modified_total_spends - self.actual_total_spends
|
| 102 |
self.delta_sales = self.modified_total_sales - self.actual_total_sales
|
| 103 |
-
|
| 104 |
def update_penalty(self, penalty):
|
| 105 |
self.penalty = penalty
|
| 106 |
|
|
@@ -111,29 +111,39 @@ class Channel:
|
|
| 111 |
self.modified_spends = (
|
| 112 |
self.modified_spends * total_spends / self.modified_spends.sum()
|
| 113 |
)
|
|
|
|
|
|
|
| 114 |
|
| 115 |
def calculate_sales(self):
|
| 116 |
-
|
|
|
|
| 117 |
return self.response_curve(self.modified_spends)
|
| 118 |
|
| 119 |
def hill_equation(x, Kd, n):
|
| 120 |
return x**n / (Kd**n + x**n)
|
| 121 |
def response_curve(self, x):
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
|
|
|
|
|
|
| 128 |
if self.response_curve_type == "hill-eq":
|
| 129 |
# dividing_parameter = check_dividing_parameter()
|
| 130 |
-
#
|
| 131 |
-
# # print(self.name)
|
|
|
|
|
|
|
|
|
|
| 132 |
if len(x) == 1:
|
| 133 |
-
dividing_rate =
|
|
|
|
| 134 |
# x = np.sum(x)
|
| 135 |
else:
|
| 136 |
dividing_rate = 1
|
|
|
|
| 137 |
# x = np.sum(x)
|
| 138 |
# dividing_rate = 104
|
| 139 |
Kd= self.response_curve_params["Kd"]
|
|
@@ -160,6 +170,9 @@ class Channel:
|
|
| 160 |
# # print(sales)
|
| 161 |
# # print(np.sum(sales))
|
| 162 |
# # print("sales",sales)
|
|
|
|
|
|
|
|
|
|
| 163 |
if self.response_curve_type == "s-curve":
|
| 164 |
if self.power >= 0:
|
| 165 |
x = x / 10**self.power
|
|
@@ -260,7 +273,7 @@ class Scenario:
|
|
| 260 |
def calculate_modified_total_spends(self):
|
| 261 |
total_actual_spends = 0.0
|
| 262 |
for channel in self.channels.values():
|
| 263 |
-
total_actual_spends += channel.actual_total_spends *
|
| 264 |
return total_actual_spends
|
| 265 |
|
| 266 |
def calculate_modified_total_spends(self):
|
|
@@ -269,13 +282,14 @@ class Scenario:
|
|
| 269 |
# import streamlit as st
|
| 270 |
# st.write(channel.modified_total_spends )
|
| 271 |
total_modified_spends += (
|
| 272 |
-
channel.modified_total_spends *
|
|
|
|
| 273 |
)
|
| 274 |
return total_modified_spends
|
| 275 |
|
| 276 |
def calculate_actual_total_sales(self):
|
| 277 |
total_actual_sales = 0#self.constant.sum() + self.correction.sum()
|
| 278 |
-
print("a")
|
| 279 |
for channel in self.channels.values():
|
| 280 |
total_actual_sales += channel.actual_total_sales
|
| 281 |
# # print(channel.actual_total_sales)
|
|
@@ -343,16 +357,7 @@ class Scenario:
|
|
| 343 |
|
| 344 |
# return zip(channels_list, res.x)
|
| 345 |
|
| 346 |
-
|
| 347 |
-
return x**n / (Kd**n + x**n)
|
| 348 |
-
|
| 349 |
-
def cost_func(channel,x):
|
| 350 |
-
x_inp = (x/104 - param_dicts["x_min"][channel]) / (param_dicts["x_max"][channel] - param_dicts["x_min"][channel])
|
| 351 |
-
# # print(x_inp)
|
| 352 |
-
x_out = hill_equation(x_inp, param_dicts["Kd"][channel], param_dicts["n"][channel])
|
| 353 |
-
# # print(x_out)
|
| 354 |
-
#
|
| 355 |
-
return (param_dicts["y_max"][channel] - param_dicts["y_min"][channel])*(x_out + param_dicts["y_min"][channel])*104
|
| 356 |
|
| 357 |
|
| 358 |
|
|
@@ -393,10 +398,10 @@ class Scenario:
|
|
| 393 |
|
| 394 |
for channel_name, modified_spends in zip(channels_list, res.x):
|
| 395 |
self.update(channel_name, modified_spends)
|
| 396 |
-
|
| 397 |
return zip(channels_list, res.x)
|
| 398 |
|
| 399 |
-
|
| 400 |
|
| 401 |
def optimize(self, spends_percent, channels_list):
|
| 402 |
# channels_list = self.channels.keys()
|
|
@@ -406,17 +411,18 @@ class Scenario:
|
|
| 406 |
for channel_name in channels_list:
|
| 407 |
# spends_constraint += self.channels[channel_name].modified_total_spends
|
| 408 |
spends_constant.append(self.channels[channel_name].conversion_rate)
|
|
|
|
| 409 |
spends_constraint += (
|
| 410 |
self.channels[channel_name].actual_total_spends
|
| 411 |
-
*
|
| 412 |
)
|
| 413 |
spends_constraint = spends_constraint * (1 + spends_percent / 100)
|
| 414 |
-
|
| 415 |
-
constraint = LinearConstraint(
|
| 416 |
-
|
| 417 |
-
|
| 418 |
-
|
| 419 |
-
)
|
| 420 |
bounds = []
|
| 421 |
old_spends = []
|
| 422 |
for channel_name in channels_list:
|
|
@@ -426,14 +432,41 @@ class Scenario:
|
|
| 426 |
(1 + spends_percent / 100)
|
| 427 |
)
|
| 428 |
old_spends.append(channel_actual_total_spends)
|
| 429 |
-
bounds.append((1+ channel_bounds / 100) * channel_actual_total_spends)
|
| 430 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 431 |
def objective_function(x):
|
|
|
|
| 432 |
for channel_name, modified_spends in zip(channels_list, x):
|
| 433 |
-
|
|
|
|
| 434 |
return -1 * self.modified_total_sales
|
| 435 |
|
| 436 |
-
|
| 437 |
# # print("$"*100)
|
| 438 |
res = minimize(
|
| 439 |
lambda x: objective_function(x) / 1e3,
|
|
@@ -441,7 +474,7 @@ class Scenario:
|
|
| 441 |
x0=old_spends,
|
| 442 |
constraints=constraint,
|
| 443 |
bounds=bounds,
|
| 444 |
-
options={"maxiter": int(1e7), "xtol":
|
| 445 |
)
|
| 446 |
# res = dual_annealing(
|
| 447 |
# objective_function,
|
|
@@ -454,6 +487,7 @@ class Scenario:
|
|
| 454 |
# # print(res)
|
| 455 |
for channel_name, modified_spends in zip(channels_list, res.x):
|
| 456 |
self.update(channel_name, modified_spends)
|
|
|
|
| 457 |
|
| 458 |
return zip(channels_list, res.x)
|
| 459 |
|
|
@@ -461,18 +495,7 @@ class Scenario:
|
|
| 461 |
def hill_equation(self,x, Kd, n):
|
| 462 |
return x**n / (Kd**n + x**n)
|
| 463 |
|
| 464 |
-
|
| 465 |
-
|
| 466 |
-
response_curve_params = pd.read_excel("response_curves_parameters.xlsx",index_col = "channel")
|
| 467 |
-
param_dicts = {col: response_curve_params[col].to_dict() for col in response_curve_params.columns}
|
| 468 |
-
|
| 469 |
-
x_inp = (x/104 - param_dicts["x_min"][channel]) / (param_dicts["x_max"][channel] - param_dicts["x_min"][channel])
|
| 470 |
-
# # print(x_inp)
|
| 471 |
-
x_out = self.hill_equation(x_inp, param_dicts["Kd"][channel], param_dicts["n"][channel])
|
| 472 |
-
# # print(x_out)
|
| 473 |
-
#
|
| 474 |
-
return (param_dicts["y_max"][channel] - param_dicts["y_min"][channel])*(x_out + param_dicts["y_min"][channel])*104
|
| 475 |
-
|
| 476 |
|
| 477 |
# def spends_optimisation(self, spends_percent,channels_list):
|
| 478 |
# m = GEKKO(remote=False)
|
|
|
|
| 100 |
self.modified_total_sales = self.modified_sales.sum()
|
| 101 |
self.delta_spends = self.modified_total_spends - self.actual_total_spends
|
| 102 |
self.delta_sales = self.modified_total_sales - self.actual_total_sales
|
| 103 |
+
# print(self.actual_total_spends)
|
| 104 |
def update_penalty(self, penalty):
|
| 105 |
self.penalty = penalty
|
| 106 |
|
|
|
|
| 111 |
self.modified_spends = (
|
| 112 |
self.modified_spends * total_spends / self.modified_spends.sum()
|
| 113 |
)
|
| 114 |
+
print("modified spends")
|
| 115 |
+
print(self.modified_spends)
|
| 116 |
|
| 117 |
def calculate_sales(self):
|
| 118 |
+
print("in calc_sales")
|
| 119 |
+
print(self.modified_spends)
|
| 120 |
return self.response_curve(self.modified_spends)
|
| 121 |
|
| 122 |
def hill_equation(x, Kd, n):
|
| 123 |
return x**n / (Kd**n + x**n)
|
| 124 |
def response_curve(self, x):
|
| 125 |
+
print(x)
|
| 126 |
+
# if self.penalty:
|
| 127 |
+
# print("in penalty")
|
| 128 |
+
# x = np.where(
|
| 129 |
+
# x < self.upper_limit,
|
| 130 |
+
# x,
|
| 131 |
+
# self.upper_limit + (x - self.upper_limit) * self.upper_limit / x,
|
| 132 |
+
# )
|
| 133 |
if self.response_curve_type == "hill-eq":
|
| 134 |
# dividing_parameter = check_dividing_parameter()
|
| 135 |
+
# print("lalala")
|
| 136 |
+
# # print(self.name)\
|
| 137 |
+
# print(len(x))
|
| 138 |
+
print("in response curve function")
|
| 139 |
+
print(x)
|
| 140 |
if len(x) == 1:
|
| 141 |
+
dividing_rate = self.response_curve_params["num_pos_obsv"]
|
| 142 |
+
# print(dividing_rate)
|
| 143 |
# x = np.sum(x)
|
| 144 |
else:
|
| 145 |
dividing_rate = 1
|
| 146 |
+
# dividing_rate = self.response_curve_params["num_pos_obsv"]
|
| 147 |
# x = np.sum(x)
|
| 148 |
# dividing_rate = 104
|
| 149 |
Kd= self.response_curve_params["Kd"]
|
|
|
|
| 170 |
# # print(sales)
|
| 171 |
# # print(np.sum(sales))
|
| 172 |
# # print("sales",sales)
|
| 173 |
+
print("aa")
|
| 174 |
+
print(sales)
|
| 175 |
+
print("aa1")
|
| 176 |
if self.response_curve_type == "s-curve":
|
| 177 |
if self.power >= 0:
|
| 178 |
x = x / 10**self.power
|
|
|
|
| 273 |
def calculate_modified_total_spends(self):
|
| 274 |
total_actual_spends = 0.0
|
| 275 |
for channel in self.channels.values():
|
| 276 |
+
total_actual_spends += channel.actual_total_spends * 1.0
|
| 277 |
return total_actual_spends
|
| 278 |
|
| 279 |
def calculate_modified_total_spends(self):
|
|
|
|
| 282 |
# import streamlit as st
|
| 283 |
# st.write(channel.modified_total_spends )
|
| 284 |
total_modified_spends += (
|
| 285 |
+
channel.modified_total_spends * 1.0
|
| 286 |
+
|
| 287 |
)
|
| 288 |
return total_modified_spends
|
| 289 |
|
| 290 |
def calculate_actual_total_sales(self):
|
| 291 |
total_actual_sales = 0#self.constant.sum() + self.correction.sum()
|
| 292 |
+
# print("a")
|
| 293 |
for channel in self.channels.values():
|
| 294 |
total_actual_sales += channel.actual_total_sales
|
| 295 |
# # print(channel.actual_total_sales)
|
|
|
|
| 357 |
|
| 358 |
# return zip(channels_list, res.x)
|
| 359 |
|
| 360 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 361 |
|
| 362 |
|
| 363 |
|
|
|
|
| 398 |
|
| 399 |
for channel_name, modified_spends in zip(channels_list, res.x):
|
| 400 |
self.update(channel_name, modified_spends)
|
| 401 |
+
|
| 402 |
return zip(channels_list, res.x)
|
| 403 |
|
| 404 |
+
|
| 405 |
|
| 406 |
def optimize(self, spends_percent, channels_list):
|
| 407 |
# channels_list = self.channels.keys()
|
|
|
|
| 411 |
for channel_name in channels_list:
|
| 412 |
# spends_constraint += self.channels[channel_name].modified_total_spends
|
| 413 |
spends_constant.append(self.channels[channel_name].conversion_rate)
|
| 414 |
+
# print(spends_constant)
|
| 415 |
spends_constraint += (
|
| 416 |
self.channels[channel_name].actual_total_spends
|
| 417 |
+
* 1.0
|
| 418 |
)
|
| 419 |
spends_constraint = spends_constraint * (1 + spends_percent / 100)
|
| 420 |
+
constraint= LinearConstraint(np.ones((num_channels,)), lb = spends_constraint, ub = spends_constraint)
|
| 421 |
+
# constraint = LinearConstraint(
|
| 422 |
+
# np.array(spends_constant),
|
| 423 |
+
# lb=spends_constraint,
|
| 424 |
+
# ub=spends_constraint,
|
| 425 |
+
# )
|
| 426 |
bounds = []
|
| 427 |
old_spends = []
|
| 428 |
for channel_name in channels_list:
|
|
|
|
| 432 |
(1 + spends_percent / 100)
|
| 433 |
)
|
| 434 |
old_spends.append(channel_actual_total_spends)
|
| 435 |
+
# bounds.append((1+ channel_bounds / 100) * channel_actual_total_spends)
|
| 436 |
+
lb = (1- _channel_class.channel_bounds_min / 100) * channel_actual_total_spends
|
| 437 |
+
ub = (1+ _channel_class.channel_bounds_max / 100) * channel_actual_total_spends
|
| 438 |
+
bounds.append((lb,ub))
|
| 439 |
+
# _channel_class.channel_bounds_min
|
| 440 |
+
# _channel_class.channel_bounds_max
|
| 441 |
+
def cost_func1(channel,x):
|
| 442 |
+
response_curve_params = pd.read_excel("response_curves_parameters.xlsx",index_col = "channel")
|
| 443 |
+
param_dicts = {col: response_curve_params[col].to_dict() for col in response_curve_params.columns}
|
| 444 |
+
|
| 445 |
+
Kd= param_dicts["Kd"][channel]
|
| 446 |
+
n= param_dicts["n"][channel]
|
| 447 |
+
x_min= param_dicts["x_min"][channel]
|
| 448 |
+
x_max= param_dicts["x_max"][channel]
|
| 449 |
+
y_min= param_dicts["y_min"][channel]
|
| 450 |
+
y_max= param_dicts['y_max'][channel]
|
| 451 |
+
division_parameter = param_dicts['num_pos_obsv'][channel]
|
| 452 |
+
x_inp = ( x/division_parameter- x_min) / (x_max - x_min)
|
| 453 |
+
# print(x_inp)
|
| 454 |
+
x_out = x_inp**n / (Kd**n + x_inp**n)
|
| 455 |
+
x_val_inv = (x_out*x_max + (1 - x_out) * x_min)
|
| 456 |
+
sales = (x_val_inv*y_min/y_max)*division_parameter
|
| 457 |
+
if np.isnan(sales):
|
| 458 |
+
# print(sales,channel)
|
| 459 |
+
sales = 0
|
| 460 |
+
# print(sales,channel)
|
| 461 |
+
return sales
|
| 462 |
def objective_function(x):
|
| 463 |
+
modified_total_sales = 0
|
| 464 |
for channel_name, modified_spends in zip(channels_list, x):
|
| 465 |
+
modified_total_sales = modified_total_sales + cost_func1(channel_name,modified_spends)
|
| 466 |
+
# self.update(channel_name, modified_spends)
|
| 467 |
return -1 * self.modified_total_sales
|
| 468 |
|
| 469 |
+
print(bounds)
|
| 470 |
# # print("$"*100)
|
| 471 |
res = minimize(
|
| 472 |
lambda x: objective_function(x) / 1e3,
|
|
|
|
| 474 |
x0=old_spends,
|
| 475 |
constraints=constraint,
|
| 476 |
bounds=bounds,
|
| 477 |
+
options={"maxiter": int(1e7), "xtol": 0.1},
|
| 478 |
)
|
| 479 |
# res = dual_annealing(
|
| 480 |
# objective_function,
|
|
|
|
| 487 |
# # print(res)
|
| 488 |
for channel_name, modified_spends in zip(channels_list, res.x):
|
| 489 |
self.update(channel_name, modified_spends)
|
| 490 |
+
print(channel_name, modified_spends,cost_func1(channel_name, modified_spends))
|
| 491 |
|
| 492 |
return zip(channels_list, res.x)
|
| 493 |
|
|
|
|
| 495 |
def hill_equation(self,x, Kd, n):
|
| 496 |
return x**n / (Kd**n + x**n)
|
| 497 |
|
| 498 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 499 |
|
| 500 |
# def spends_optimisation(self, spends_percent,channels_list):
|
| 501 |
# m = GEKKO(remote=False)
|
pages/1_Model_Quality.py
CHANGED
|
@@ -16,7 +16,7 @@ st.plotly_chart(sf.mmm_model_quality(),use_container_width=True)
|
|
| 16 |
|
| 17 |
media_df = sf.media_data()
|
| 18 |
# Create two columns for start date and end date input
|
| 19 |
-
col1, col2 , col3 = st.columns([1,
|
| 20 |
df1 = sf.model_metrics_table_func()
|
| 21 |
st.dataframe(df1,hide_index = True,use_container_width=True)
|
| 22 |
|
|
|
|
| 16 |
|
| 17 |
media_df = sf.media_data()
|
| 18 |
# Create two columns for start date and end date input
|
| 19 |
+
col1, col2 , col3 = st.columns([1,0.2,1])
|
| 20 |
df1 = sf.model_metrics_table_func()
|
| 21 |
st.dataframe(df1,hide_index = True,use_container_width=True)
|
| 22 |
|
pages/2_Scenario_Planner.py
CHANGED
|
@@ -98,6 +98,9 @@ def optimize(key, status_placeholder):
|
|
| 98 |
# result = st.session_state["scenario"].spends_optimisation(
|
| 99 |
# st.session_state["total_spends_change"], channel_list
|
| 100 |
)
|
|
|
|
|
|
|
|
|
|
| 101 |
|
| 102 |
|
| 103 |
# elif key.lower() == "revenue":
|
|
@@ -111,7 +114,7 @@ def optimize(key, status_placeholder):
|
|
| 111 |
for channel_name, modified_spends in result:
|
| 112 |
|
| 113 |
st.session_state[channel_name] = numerize(
|
| 114 |
-
modified_spends *
|
| 115 |
1,
|
| 116 |
)
|
| 117 |
prev_spends = (
|
|
|
|
| 98 |
# result = st.session_state["scenario"].spends_optimisation(
|
| 99 |
# st.session_state["total_spends_change"], channel_list
|
| 100 |
)
|
| 101 |
+
print("")
|
| 102 |
+
print(list(zip(*result)))
|
| 103 |
+
|
| 104 |
|
| 105 |
|
| 106 |
# elif key.lower() == "revenue":
|
|
|
|
| 114 |
for channel_name, modified_spends in result:
|
| 115 |
|
| 116 |
st.session_state[channel_name] = numerize(
|
| 117 |
+
modified_spends * 1.0,
|
| 118 |
1,
|
| 119 |
)
|
| 120 |
prev_spends = (
|
pages/5_Glossary.py
CHANGED
|
@@ -5,29 +5,32 @@ import streamlit as st
|
|
| 5 |
# )
|
| 6 |
|
| 7 |
def glossary_run():
|
| 8 |
-
st.
|
| 9 |
-
st.
|
|
|
|
|
|
|
| 10 |
|
| 11 |
-
|
| 12 |
|
| 13 |
-
|
| 14 |
|
| 15 |
-
|
| 16 |
|
| 17 |
-
|
| 18 |
|
| 19 |
-
|
| 20 |
|
| 21 |
-
|
| 22 |
|
| 23 |
-
|
| 24 |
|
| 25 |
-
|
| 26 |
|
| 27 |
-
|
| 28 |
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
st.write("**• Estimated CPC \(Cost Per Click\):** This is an estimation of the cost for each time someone clicks on its advertisement via that media channel. The default values are generated from historical averages.")
|
| 32 |
|
|
|
|
|
|
|
|
|
|
| 33 |
glossary_run()
|
|
|
|
| 5 |
# )
|
| 6 |
|
| 7 |
def glossary_run():
|
| 8 |
+
st.header("Glossary")
|
| 9 |
+
with st.expander("Model MMM Terminology"):
|
| 10 |
+
st.subheader("Glossary of MMM Terminology")
|
| 11 |
+
st.write("**• Model R-squared \(R\)\:** This is a statistical measure used to determine the percentage of variation in the dependent variable that the independent variables explain collectively. It ranges between 0 and 1, where 1 indicates a perfect fit and 0 indicates no linear relationship. An R2 greater than 0.8 usually indicates a great model fit.")
|
| 12 |
|
| 13 |
+
st.write("**• Mean Absolute Percentage Error \(MAPE\):** This is a measure used to determine the accuracy of a predictive model. It calculates the average absolute percentage difference between the actual and predicted values, expressing the result as a percentage to provide a sense of scale for the error.")
|
| 14 |
|
| 15 |
+
st.write("**• Media & Baseline Elasticity:** It refers to the percentage change in the number of prospects in response to a percentage change in a marketing input \(media channel spends\) or a baseline factor \(like seasonality. macro factors, competitors spending, etc.\). It is a measure of the responsiveness of the number of prospects to changes in the marketing input or the baseline factor")
|
| 16 |
|
| 17 |
+
st.write("**• Media Half-Life:** This represents the time it takes for a media spend's impact to reduce to half of its initial impact. It is a key aspect of media decay rates, which represent how the effect of advertising diminishes over time \(in weeks\). This term refers to a curve that illustrates the relationship between media spend and the resulting number of prospects.")
|
| 18 |
|
| 19 |
+
st.write("**• Support:** Equivalent to Impression or Click depending on the media channel.")
|
| 20 |
|
| 21 |
+
st.write("**• Contribution Share:** Unit is %. It refers to the percentage contribution of a specific marketing channel to the number of prospects. It is calculated by dividing the contribution from a particular channel by the total number of prospects from all media channels \(not including base contributions\).")
|
| 22 |
|
| 23 |
+
st.write("**• Spend Share:** Unit is %. It refers to the percentage of the total marketing budget that is allocated to a specific marketing channel. It is calculated by dividing the amount spent on a particular channel by the total marketing spend")
|
| 24 |
|
| 25 |
+
st.write("**• Support Share:** Unit is %. It refers to the percentage of the total media impression that is allocated to a specific marketing channel. It is calculated by dividing support on a particular channel by the total marketing spend")
|
| 26 |
|
| 27 |
+
st.write("**• Efficiency Index:** it is a metric that measures the cost-effectiveness of a campaign. It is calculated by dividing Contribution Share by Spend Share. An efficiency index above 1 suggests that a channel is more cost-effective than the benchmark, while an efficiency index below 1 suggests it is less cost-effective. The higher the efficiency index, the more cost-effective its channel is")
|
| 28 |
|
| 29 |
+
st.write("**• Effectiveness Index:** It is a metric that measures how well a particular marketing channel is performing relative to its support/impression. It is calculated by dividing the Contribution Share by the Spend Share for each channel")
|
| 30 |
|
| 31 |
+
st.write("**• Estimated CPM \(Cost Per Thousand Impressions\):** This is an estimation of the cost for every thousand impressions \(or views\) of its advertisement via that media channel. The default values are generated from historical averages.")
|
|
|
|
|
|
|
| 32 |
|
| 33 |
+
st.write("**• Estimated CPC \(Cost Per Click\):** This is an estimation of the cost for each time someone clicks on its advertisement via that media channel. The default values are generated from historical averages.")
|
| 34 |
+
with st.expander("Deployment Plan"):
|
| 35 |
+
st.image(r"C:\Users\PragyaJatav\Downloads\image (2).png")
|
| 36 |
glossary_run()
|
response_curves_parameters.xlsx
CHANGED
|
Binary files a/response_curves_parameters.xlsx and b/response_curves_parameters.xlsx differ
|
|
|
summary_df.pkl
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
size 1822
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:02f8f23713eadad9c91bae3af6649f9f2e7e2aa8d73fb28986bd48903cb74f38
|
| 3 |
size 1822
|
utilities.py
CHANGED
|
@@ -335,7 +335,7 @@ def initialize_data(
|
|
| 335 |
spends=spends,
|
| 336 |
sales= y.copy(),
|
| 337 |
# conversion_rate = np.mean(list(conv_rates[inp_col].values())),
|
| 338 |
-
conversion_rate=conv_rates[inp_col],
|
| 339 |
response_curve_type="hill-eq",
|
| 340 |
response_curve_params={
|
| 341 |
"Kd": param_dicts["Kd"][inp_col],
|
|
@@ -343,7 +343,8 @@ def initialize_data(
|
|
| 343 |
"x_min": param_dicts["x_min"][inp_col],
|
| 344 |
"x_max": param_dicts["x_max"][inp_col],
|
| 345 |
"y_min": param_dicts["y_min"][inp_col],
|
| 346 |
-
"y_max": param_dicts["y_max"][inp_col]
|
|
|
|
| 347 |
},
|
| 348 |
bounds=np.array([-10, 10]),
|
| 349 |
channel_bounds_min = 10,
|
|
@@ -387,7 +388,7 @@ def initialize_data(
|
|
| 387 |
|
| 388 |
for channel in channels.values():
|
| 389 |
st.session_state[channel.name] = numerize(
|
| 390 |
-
channel.actual_total_spends *
|
| 391 |
)
|
| 392 |
|
| 393 |
st.session_state["xlsx_buffer"] = io.BytesIO()
|
|
|
|
| 335 |
spends=spends,
|
| 336 |
sales= y.copy(),
|
| 337 |
# conversion_rate = np.mean(list(conv_rates[inp_col].values())),
|
| 338 |
+
conversion_rate=1.0 ,#conv_rates[inp_col],
|
| 339 |
response_curve_type="hill-eq",
|
| 340 |
response_curve_params={
|
| 341 |
"Kd": param_dicts["Kd"][inp_col],
|
|
|
|
| 343 |
"x_min": param_dicts["x_min"][inp_col],
|
| 344 |
"x_max": param_dicts["x_max"][inp_col],
|
| 345 |
"y_min": param_dicts["y_min"][inp_col],
|
| 346 |
+
"y_max": param_dicts["y_max"][inp_col],
|
| 347 |
+
"num_pos_obsv":param_dicts["num_pos_obsv"][inp_col]
|
| 348 |
},
|
| 349 |
bounds=np.array([-10, 10]),
|
| 350 |
channel_bounds_min = 10,
|
|
|
|
| 388 |
|
| 389 |
for channel in channels.values():
|
| 390 |
st.session_state[channel.name] = numerize(
|
| 391 |
+
channel.actual_total_spends * 1.0, 1
|
| 392 |
)
|
| 393 |
|
| 394 |
st.session_state["xlsx_buffer"] = io.BytesIO()
|