Spaces:
Sleeping
Sleeping
Commit
·
78153ba
1
Parent(s):
047c64c
feat: updated website
Browse files
app.py
CHANGED
@@ -241,7 +241,6 @@ if page == "Summary":
|
|
241 |
)}
|
242 |
)
|
243 |
# Customer Analysis Page
|
244 |
-
|
245 |
elif page == "Customer Analysis":
|
246 |
st.markdown("""
|
247 |
<h2 style='text-align: center; font-size: 2.5rem;'>Customer Analysis</h2>
|
@@ -281,14 +280,12 @@ elif page == "Customer Analysis":
|
|
281 |
# Convert cliente_id to string
|
282 |
predict_data['cliente_id'] = predict_data['cliente_id'].astype(str)
|
283 |
|
284 |
-
with st.spinner("Filtering data..."):
|
285 |
-
|
286 |
# Filter for the specific customer
|
287 |
customer_code_str = str(customer_code)
|
288 |
customer_data = predict_data[predict_data['cliente_id'] == customer_code_str]
|
289 |
|
290 |
-
with st.spinner("Generating sales predictions..."):
|
291 |
-
|
292 |
if not customer_data.empty:
|
293 |
# Define features consistently with the training process
|
294 |
lag_features = [f'precio_total_lag_{lag}' for lag in range(1, 25)]
|
@@ -309,7 +306,7 @@ elif page == "Customer Analysis":
|
|
309 |
results = customer_data[['cliente_id', 'marca_id_encoded', 'fecha_mes']].copy()
|
310 |
results['ventas_predichas'] = y_pred
|
311 |
|
312 |
-
# Load actual data
|
313 |
actual_sales = df_agg_2024[df_agg_2024['cliente_id'] == customer_code_str]
|
314 |
|
315 |
if not actual_sales.empty:
|
@@ -321,7 +318,7 @@ elif page == "Customer Analysis":
|
|
321 |
else:
|
322 |
# If no actual sales data for 2024, fill 'ventas_reales' with 0
|
323 |
results['ventas_reales'] = 0
|
324 |
-
|
325 |
# Ensure any missing sales data is filled with 0
|
326 |
results['ventas_reales'].fillna(0, inplace=True)
|
327 |
|
@@ -409,7 +406,9 @@ elif page == "Customer Analysis":
|
|
409 |
|
410 |
st.plotly_chart(fig_comparison, use_container_width=True)
|
411 |
|
412 |
-
#
|
|
|
|
|
413 |
sales_columns = ['VENTA_2021', 'VENTA_2022', 'VENTA_2023']
|
414 |
if all(col in ventas_clientes.columns for col in sales_columns):
|
415 |
customer_sales_data = ventas_clientes[ventas_clientes['codigo_cliente'] == customer_code]
|
@@ -420,47 +419,39 @@ elif page == "Customer Analysis":
|
|
420 |
|
421 |
# Add the 2024 actual and predicted data
|
422 |
if 'ventas_predichas' in results.columns and 'ventas_reales' in results.columns:
|
423 |
-
# Get the actual and predicted sales for 2024
|
424 |
actual_sales_2024 = results[results['fecha_mes'].str.startswith('2024')]['ventas_reales'].sum()
|
425 |
predicted_sales_2024 = results[results['fecha_mes'].str.startswith('2024')]['ventas_predichas'].sum()
|
426 |
|
427 |
-
|
428 |
-
months_available = 9 # Data available until September
|
429 |
actual_sales_2024_annual = (actual_sales_2024 / months_available) * 12
|
430 |
|
431 |
-
# Add 2024 actual and predicted sales
|
432 |
sales_values = list(customer_sales) + [actual_sales_2024_annual]
|
433 |
predicted_values = list(customer_sales) + [predicted_sales_2024]
|
434 |
|
435 |
-
# Add 2024 to the years list
|
436 |
years.append('2024')
|
437 |
|
438 |
fig_sales_bar = go.Figure()
|
439 |
-
# Add trace for historical sales (2021-2023)
|
440 |
fig_sales_bar.add_trace(go.Bar(
|
441 |
-
x=years[:3],
|
442 |
y=sales_values[:3],
|
443 |
name="Historical Sales",
|
444 |
marker_color='blue'
|
445 |
))
|
446 |
|
447 |
-
# Add trace for 2024 actual sales
|
448 |
fig_sales_bar.add_trace(go.Bar(
|
449 |
-
x=[years[3]],
|
450 |
y=[sales_values[3]],
|
451 |
name="2024 Actual Sales (Annualized)",
|
452 |
marker_color='green'
|
453 |
))
|
454 |
|
455 |
-
# Add trace for 2024 predicted sales
|
456 |
fig_sales_bar.add_trace(go.Bar(
|
457 |
-
x=[years[3]],
|
458 |
y=[predicted_values[3]],
|
459 |
name="2024 Predicted Sales",
|
460 |
marker_color='orange'
|
461 |
))
|
462 |
|
463 |
-
# Update layout
|
464 |
fig_sales_bar.update_layout(
|
465 |
title=f"Sales Over the Years for Customer {customer_code}",
|
466 |
xaxis_title="Year",
|
@@ -471,18 +462,11 @@ elif page == "Customer Analysis":
|
|
471 |
hovermode="x unified"
|
472 |
)
|
473 |
|
474 |
-
# Show the interactive bar chart in Streamlit
|
475 |
st.plotly_chart(fig_sales_bar, use_container_width=True)
|
476 |
|
477 |
else:
|
478 |
st.warning(f"No predicted or actual data found for customer {customer_code} for 2024.")
|
479 |
|
480 |
-
else:
|
481 |
-
st.warning(f"No historical sales data found for customer {customer_code}")
|
482 |
-
|
483 |
-
else:
|
484 |
-
st.warning("Sales data for 2021-2023 not available in the dataset.")
|
485 |
-
|
486 |
|
487 |
|
488 |
# elif page == "Customer Analysis":
|
@@ -925,141 +909,3 @@ elif page == "Articles Recommendations":
|
|
925 |
# else:
|
926 |
# st.warning("Please select at least one article and set its quantity.")
|
927 |
|
928 |
-
|
929 |
-
# Customer Analysis Page
|
930 |
-
# elif page == "Customer Analysis":
|
931 |
-
# st.title("Customer Analysis")
|
932 |
-
# st.markdown("Use the tools below to explore your customer data.")
|
933 |
-
|
934 |
-
# partial_code = st.text_input("Enter part of Customer Code (or leave empty to see all)")
|
935 |
-
# if partial_code:
|
936 |
-
# filtered_customers = df[df['CLIENTE'].str.contains(partial_code)]
|
937 |
-
# else:
|
938 |
-
# filtered_customers = df
|
939 |
-
# customer_list = filtered_customers['CLIENTE'].unique()
|
940 |
-
# customer_code = st.selectbox("Select Customer Code", customer_list)
|
941 |
-
|
942 |
-
# if st.button("Calcular"):
|
943 |
-
# if customer_code:
|
944 |
-
# # Find Customer's Cluster
|
945 |
-
# customer_match = customer_clusters[customer_clusters['cliente_id'] == customer_code]
|
946 |
-
|
947 |
-
# if not customer_match.empty:
|
948 |
-
# cluster = customer_match['cluster_id'].values[0]
|
949 |
-
# st.write(f"Customer {customer_code} belongs to cluster {cluster}")
|
950 |
-
|
951 |
-
# # Load the Corresponding Model
|
952 |
-
# model_path = f'models/modelo_cluster_{cluster}.txt'
|
953 |
-
# gbm = lgb.Booster(model_file=model_path)
|
954 |
-
# st.write(f"Loaded model for cluster {cluster}")
|
955 |
-
|
956 |
-
# # Load X_predict for that cluster
|
957 |
-
# X_predict_cluster = pd.read_csv(f'predicts/X_predict_cluster_{cluster}.csv')
|
958 |
-
|
959 |
-
# # Filter for the specific customer
|
960 |
-
# X_cliente = X_predict_cluster[X_predict_cluster['cliente_id'] == customer_code]
|
961 |
-
|
962 |
-
# if not X_cliente.empty:
|
963 |
-
# # Prepare data for prediction
|
964 |
-
# features_for_prediction = X_cliente.drop(columns=['cliente_id', 'fecha_mes'])
|
965 |
-
|
966 |
-
# # Make Prediction for the selected customer
|
967 |
-
# y_pred = gbm.predict(features_for_prediction, num_iteration=gbm.best_iteration)
|
968 |
-
|
969 |
-
# # Reassemble the results
|
970 |
-
# results = X_cliente[['cliente_id', 'marca_id_encoded', 'fecha_mes']].copy()
|
971 |
-
# results['ventas_predichas'] = y_pred
|
972 |
-
|
973 |
-
# st.write(f"Predicted total sales for Customer {customer_code}: {results['ventas_predichas'].sum():.2f}")
|
974 |
-
|
975 |
-
# # Load actual data
|
976 |
-
# df_agg_2024 = pd.read_csv('predicts/df_agg_2024.csv')
|
977 |
-
# actual_sales = df_agg_2024[df_agg_2024['cliente_id'] == customer_code]
|
978 |
-
|
979 |
-
# if not actual_sales.empty:
|
980 |
-
# results = results.merge(actual_sales[['cliente_id', 'marca_id_encoded', 'fecha_mes', 'precio_total']],
|
981 |
-
# on=['cliente_id', 'marca_id_encoded', 'fecha_mes'],
|
982 |
-
# how='left')
|
983 |
-
# results.rename(columns={'precio_total': 'ventas_reales'}, inplace=True)
|
984 |
-
|
985 |
-
# # Calculate metrics only for non-null actual sales
|
986 |
-
# valid_results = results.dropna(subset=['ventas_reales'])
|
987 |
-
# if not valid_results.empty:
|
988 |
-
# mae = mean_absolute_error(valid_results['ventas_reales'], valid_results['ventas_predichas'])
|
989 |
-
# mape = np.mean(np.abs((valid_results['ventas_reales'] - valid_results['ventas_predichas']) / valid_results['ventas_reales'])) * 100
|
990 |
-
# rmse = np.sqrt(mean_squared_error(valid_results['ventas_reales'], valid_results['ventas_predichas']))
|
991 |
-
|
992 |
-
# st.write(f"Actual total sales for Customer {customer_code}: {valid_results['ventas_reales'].sum():.2f}")
|
993 |
-
# st.write(f"MAE: {mae:.2f}")
|
994 |
-
# st.write(f"MAPE: {mape:.2f}%")
|
995 |
-
# st.write(f"RMSE: {rmse:.2f}")
|
996 |
-
|
997 |
-
# # Analysis of results
|
998 |
-
# threshold_good = 100 # You may want to adjust this threshold
|
999 |
-
# if mae < threshold_good:
|
1000 |
-
# st.success(f"Customer {customer_code} is performing well based on the predictions.")
|
1001 |
-
# else:
|
1002 |
-
# st.warning(f"Customer {customer_code} is not performing well based on the predictions.")
|
1003 |
-
# else:
|
1004 |
-
# st.warning(f"No actual sales data found for customer {customer_code} in df_agg_2024.")
|
1005 |
-
|
1006 |
-
# # Show the radar chart
|
1007 |
-
# all_manufacturers = customer_data.iloc[:, 1:].T # Exclude CLIENTE column
|
1008 |
-
# all_manufacturers.index = all_manufacturers.index.astype(str)
|
1009 |
-
|
1010 |
-
# sales_data = customer_euros.iloc[:, 1:].T # Exclude CLIENTE column
|
1011 |
-
# sales_data.index = sales_data.index.astype(str)
|
1012 |
-
|
1013 |
-
# sales_data_filtered = sales_data.drop(index='CLIENTE', errors='ignore')
|
1014 |
-
# sales_data_filtered = sales_data_filtered.apply(pd.to_numeric, errors='coerce')
|
1015 |
-
|
1016 |
-
# top_units = all_manufacturers.sort_values(by=all_manufacturers.columns[0], ascending=False).head(10)
|
1017 |
-
# top_sales = sales_data_filtered.sort_values(by=sales_data_filtered.columns[0], ascending=False).head(10)
|
1018 |
-
# combined_top = pd.concat([top_units, top_sales]).index.unique()[:20]
|
1019 |
-
# combined_top = [m for m in combined_top if m in all_manufacturers.index and m in sales_data_filtered.index]
|
1020 |
-
|
1021 |
-
# combined_data = pd.DataFrame({
|
1022 |
-
# 'units': all_manufacturers.loc[combined_top, all_manufacturers.columns[0]],
|
1023 |
-
# 'sales': sales_data_filtered.loc[combined_top, sales_data_filtered.columns[0]]
|
1024 |
-
# }).fillna(0)
|
1025 |
-
|
1026 |
-
# combined_data_sorted = combined_data.sort_values(by=['units', 'sales'], ascending=False)
|
1027 |
-
# non_zero_manufacturers = combined_data_sorted[combined_data_sorted['units'] > 0]
|
1028 |
-
|
1029 |
-
# if len(non_zero_manufacturers) < 3:
|
1030 |
-
# zero_manufacturers = combined_data_sorted[combined_data_sorted['units'] == 0].head(3 - len(non_zero_manufacturers))
|
1031 |
-
# manufacturers_to_show = pd.concat([non_zero_manufacturers, zero_manufacturers])
|
1032 |
-
# else:
|
1033 |
-
# manufacturers_to_show = non_zero_manufacturers
|
1034 |
-
|
1035 |
-
# values = manufacturers_to_show['units'].tolist()
|
1036 |
-
# amounts = manufacturers_to_show['sales'].tolist()
|
1037 |
-
# manufacturers = [get_supplier_name(m) for m in manufacturers_to_show.index]
|
1038 |
-
|
1039 |
-
# st.write(f"### Results for top {len(manufacturers)} manufacturers:")
|
1040 |
-
# for manufacturer, value, amount in zip(manufacturers, values, amounts):
|
1041 |
-
# st.write(f"{manufacturer} = {value:.2f}% of units, €{amount:.2f} total sales")
|
1042 |
-
|
1043 |
-
# if manufacturers:
|
1044 |
-
# fig = radar_chart(manufacturers, values, amounts, f'Radar Chart for Top {len(manufacturers)} Manufacturers of Customer {customer_code}')
|
1045 |
-
# st.pyplot(fig)
|
1046 |
-
# else:
|
1047 |
-
# st.warning("No data available to create the radar chart.")
|
1048 |
-
|
1049 |
-
# # Show sales over the years graph
|
1050 |
-
# sales_columns = ['VENTA_2021', 'VENTA_2022', 'VENTA_2023']
|
1051 |
-
# if all(col in ventas_clientes.columns for col in sales_columns):
|
1052 |
-
# years = ['2021', '2022', '2023']
|
1053 |
-
# customer_sales = ventas_clientes[ventas_clientes['codigo_cliente'] == customer_code][sales_columns].values[0]
|
1054 |
-
|
1055 |
-
# fig_sales = px.line(x=years, y=customer_sales, markers=True, title=f'Sales Over the Years for Customer {customer_code}')
|
1056 |
-
# fig_sales.update_layout(xaxis_title="Year", yaxis_title="Sales")
|
1057 |
-
# st.plotly_chart(fig_sales)
|
1058 |
-
# else:
|
1059 |
-
# st.warning("Sales data for 2021-2023 not available.")
|
1060 |
-
# else:
|
1061 |
-
# st.warning(f"No prediction data found for customer {customer_code}.")
|
1062 |
-
# else:
|
1063 |
-
# st.warning(f"No data found for customer {customer_code}. Please check the code.")
|
1064 |
-
# else:
|
1065 |
-
# st.warning("Please select a customer.")
|
|
|
241 |
)}
|
242 |
)
|
243 |
# Customer Analysis Page
|
|
|
244 |
elif page == "Customer Analysis":
|
245 |
st.markdown("""
|
246 |
<h2 style='text-align: center; font-size: 2.5rem;'>Customer Analysis</h2>
|
|
|
280 |
# Convert cliente_id to string
|
281 |
predict_data['cliente_id'] = predict_data['cliente_id'].astype(str)
|
282 |
|
283 |
+
with st.spinner("Filtering data..."):
|
|
|
284 |
# Filter for the specific customer
|
285 |
customer_code_str = str(customer_code)
|
286 |
customer_data = predict_data[predict_data['cliente_id'] == customer_code_str]
|
287 |
|
288 |
+
with st.spinner("Generating sales predictions..."):
|
|
|
289 |
if not customer_data.empty:
|
290 |
# Define features consistently with the training process
|
291 |
lag_features = [f'precio_total_lag_{lag}' for lag in range(1, 25)]
|
|
|
306 |
results = customer_data[['cliente_id', 'marca_id_encoded', 'fecha_mes']].copy()
|
307 |
results['ventas_predichas'] = y_pred
|
308 |
|
309 |
+
# Load actual data from df_agg_2024
|
310 |
actual_sales = df_agg_2024[df_agg_2024['cliente_id'] == customer_code_str]
|
311 |
|
312 |
if not actual_sales.empty:
|
|
|
318 |
else:
|
319 |
# If no actual sales data for 2024, fill 'ventas_reales' with 0
|
320 |
results['ventas_reales'] = 0
|
321 |
+
|
322 |
# Ensure any missing sales data is filled with 0
|
323 |
results['ventas_reales'].fillna(0, inplace=True)
|
324 |
|
|
|
406 |
|
407 |
st.plotly_chart(fig_comparison, use_container_width=True)
|
408 |
|
409 |
+
# Gráfico de ventas anuales
|
410 |
+
ventas_clientes['codigo_cliente'] = ventas_clientes['codigo_cliente'].astype(str).str.strip()
|
411 |
+
|
412 |
sales_columns = ['VENTA_2021', 'VENTA_2022', 'VENTA_2023']
|
413 |
if all(col in ventas_clientes.columns for col in sales_columns):
|
414 |
customer_sales_data = ventas_clientes[ventas_clientes['codigo_cliente'] == customer_code]
|
|
|
419 |
|
420 |
# Add the 2024 actual and predicted data
|
421 |
if 'ventas_predichas' in results.columns and 'ventas_reales' in results.columns:
|
|
|
422 |
actual_sales_2024 = results[results['fecha_mes'].str.startswith('2024')]['ventas_reales'].sum()
|
423 |
predicted_sales_2024 = results[results['fecha_mes'].str.startswith('2024')]['ventas_predichas'].sum()
|
424 |
|
425 |
+
months_available = 9
|
|
|
426 |
actual_sales_2024_annual = (actual_sales_2024 / months_available) * 12
|
427 |
|
|
|
428 |
sales_values = list(customer_sales) + [actual_sales_2024_annual]
|
429 |
predicted_values = list(customer_sales) + [predicted_sales_2024]
|
430 |
|
|
|
431 |
years.append('2024')
|
432 |
|
433 |
fig_sales_bar = go.Figure()
|
|
|
434 |
fig_sales_bar.add_trace(go.Bar(
|
435 |
+
x=years[:3],
|
436 |
y=sales_values[:3],
|
437 |
name="Historical Sales",
|
438 |
marker_color='blue'
|
439 |
))
|
440 |
|
|
|
441 |
fig_sales_bar.add_trace(go.Bar(
|
442 |
+
x=[years[3]],
|
443 |
y=[sales_values[3]],
|
444 |
name="2024 Actual Sales (Annualized)",
|
445 |
marker_color='green'
|
446 |
))
|
447 |
|
|
|
448 |
fig_sales_bar.add_trace(go.Bar(
|
449 |
+
x=[years[3]],
|
450 |
y=[predicted_values[3]],
|
451 |
name="2024 Predicted Sales",
|
452 |
marker_color='orange'
|
453 |
))
|
454 |
|
|
|
455 |
fig_sales_bar.update_layout(
|
456 |
title=f"Sales Over the Years for Customer {customer_code}",
|
457 |
xaxis_title="Year",
|
|
|
462 |
hovermode="x unified"
|
463 |
)
|
464 |
|
|
|
465 |
st.plotly_chart(fig_sales_bar, use_container_width=True)
|
466 |
|
467 |
else:
|
468 |
st.warning(f"No predicted or actual data found for customer {customer_code} for 2024.")
|
469 |
|
|
|
|
|
|
|
|
|
|
|
|
|
470 |
|
471 |
|
472 |
# elif page == "Customer Analysis":
|
|
|
909 |
# else:
|
910 |
# st.warning("Please select at least one article and set its quantity.")
|
911 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|