handex commited on
Commit
3f276cc
·
verified ·
1 Parent(s): 5b8c9af

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +110 -38
src/streamlit_app.py CHANGED
@@ -1,40 +1,112 @@
1
- import altair as alt
2
- import numpy as np
3
- import pandas as pd
4
  import streamlit as st
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
- """
7
- # Welcome to Streamlit!
8
-
9
- Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
10
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
11
- forums](https://discuss.streamlit.io).
12
-
13
- In the meantime, below is an example of what you can do with just a few lines of code:
14
- """
15
-
16
- num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
17
- num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
18
-
19
- indices = np.linspace(0, 1, num_points)
20
- theta = 2 * np.pi * num_turns * indices
21
- radius = indices
22
-
23
- x = radius * np.cos(theta)
24
- y = radius * np.sin(theta)
25
-
26
- df = pd.DataFrame({
27
- "x": x,
28
- "y": y,
29
- "idx": indices,
30
- "rand": np.random.randn(num_points),
31
- })
32
-
33
- st.altair_chart(alt.Chart(df, height=700, width=700)
34
- .mark_point(filled=True)
35
- .encode(
36
- x=alt.X("x", axis=None),
37
- y=alt.Y("y", axis=None),
38
- color=alt.Color("idx", legend=None, scale=alt.Scale()),
39
- size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
40
- ))
 
 
 
 
1
  import streamlit as st
2
+ import pandas as pd
3
+ import numpy as np
4
+ import joblib
5
+ import holidays
6
+ import xgboost as xgb
7
+ from datetime import date
8
+
9
+ # Load the model
10
+ @st.cache_resource
11
+ def load_artifacts():
12
+ model = joblib.load('src/xgb_model.joblib')
13
+ encoders = joblib.load('src/encoders.joblib')
14
+ return model, encoders
15
+
16
+ try:
17
+ model, encoders = load_artifacts()
18
+ except FileNotFoundError:
19
+ st.error("Model files not found. Please upload 'xgb_model.joblib' and 'encoders.joblib'.")
20
+ st.stop()
21
+
22
+ # Feature Engineering
23
+ def create_features(df):
24
+ df = df.copy()
25
+ df['date'] = pd.to_datetime(df['date'])
26
+ df['year'] = df['date'].dt.year
27
+ df['month'] = df['date'].dt.month
28
+ df['day'] = df['date'].dt.day
29
+ df['day_of_week'] = df['date'].dt.dayofweek
30
+ df['day_of_year'] = df['date'].dt.dayofyear
31
+ df['week_of_year'] = df['date'].dt.isocalendar().week.astype(int)
32
+ df['is_weekend'] = (df['day_of_week'] >= 5).astype(int)
33
+
34
+ # Cyclical Encoding
35
+ df['day_sin'] = np.sin(2 * np.pi * df['day_of_year'] / 365.0)
36
+ df['day_cos'] = np.cos(2 * np.pi * df['day_of_year'] / 365.0)
37
+ df['month_sin'] = np.sin(2 * np.pi * df['month'] / 12.0)
38
+ df['month_cos'] = np.cos(2 * np.pi * df['month'] / 12.0)
39
+
40
+ return df
41
+
42
+ def add_holiday_features(df, encoders):
43
+ df = df.copy()
44
+ # Inverse transform to get country names for holiday library
45
+ df['country_name'] = encoders['country'].inverse_transform(df['country'])
46
+ years = df['date'].dt.year.unique()
47
+ country_codes = {'Canada': 'CA','Finland': 'FI','Italy': 'IT','Kenya': 'KE','Norway': 'NO','Singapore': 'SG'}
48
+
49
+ df['is_holiday'] = 0
50
+
51
+ for country_name, code in country_codes.items():
52
+ try:
53
+ country_holidays = holidays.Country(code, years=years)
54
+ mask = (df['country_name'] == country_name) & (df['date'].isin(country_holidays))
55
+ df.loc[mask, 'is_holiday'] = 1
56
+ except:
57
+ continue
58
+ df = df.drop(columns=['country_name'])
59
+ return df
60
+
61
+ # UI
62
+ st.title("🛒 Sticker Sales Prediction")
63
+ st.write("Enter the details below to predict the number of items sold.")
64
+
65
+ # Input
66
+ col1, col2 = st.columns(2)
67
+
68
+ with col1:
69
+ country_options = list(encoders['country'].classes_)
70
+ store_options = list(encoders['store'].classes_)
71
+ product_options = list(encoders['product'].classes_)
72
+
73
+ selected_date = st.date_input("Select Date", value=date(2025, 1, 1))
74
+ selected_country = st.selectbox("Select Country", country_options)
75
+
76
+ with col2:
77
+ selected_store = st.selectbox("Select Store", store_options)
78
+ selected_product = st.selectbox("Select Product", product_options)
79
 
80
+ # 4. Prediction Button
81
+ if st.button("Predict Sales"):
82
+ input_data = pd.DataFrame({
83
+ 'date': [pd.to_datetime(selected_date)],
84
+ 'country': [selected_country],
85
+ 'store': [selected_store],
86
+ 'product': [selected_product]})
87
+
88
+ processed_data = create_features(input_data)
89
+ categorical_cols = ['country', 'store', 'product']
90
+ for col in categorical_cols:
91
+ processed_data[col] = encoders[col].transform(processed_data[col])
92
+ processed_data = add_holiday_features(processed_data, encoders)
93
+
94
+ features = ['country', 'store', 'product', 'year', 'month', 'day', 'day_of_week', 'day_of_year', 'is_weekend',
95
+ 'day_sin', 'day_cos', 'month_sin', 'month_cos', 'is_holiday']
96
+
97
+ X_input = processed_data[features]
98
+
99
+ # Prediction
100
+ try:
101
+ pred_log = model.predict(X_input)
102
+
103
+ final_prediction = np.expm1(pred_log)[0]
104
+ final_prediction = max(0, final_prediction) # Ensure no negative sales
105
+
106
+ st.success(f"Predicted Num Sold: **{final_prediction:.2f}**")
107
+
108
+ with st.expander("See processed features"):
109
+ st.dataframe(X_input)
110
+
111
+ except Exception as e:
112
+ st.error(f"An error occurred during prediction: {e}")