EnYa32 commited on
Commit
fe53f63
·
verified ·
1 Parent(s): a702e83

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +134 -36
src/streamlit_app.py CHANGED
@@ -1,40 +1,138 @@
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 numpy as np
2
  import pandas as pd
3
  import streamlit as st
4
+ import joblib
5
+ from pathlib import Path
6
 
7
+ # -------------------------------
8
+ # Page config
9
+ # -------------------------------
10
+ st.set_page_config(
11
+ page_title='Rainfall Probability Predictor (LogReg)',
12
+ page_icon='🌧️',
13
+ layout='centered'
14
+ )
15
+
16
+ st.title('🌧️ Rainfall Probability Predictor')
17
+ st.write('Predicts the probability of rainfall (0–1) using a Logistic Regression model trained on weather features.')
18
+
19
+ BASE_DIR = Path(__file__).resolve().parent
20
+ MODEL_PATH = BASE_DIR / 'logistic_regression_model.pkl'
21
+ FEATURE_NAMES_PATH = BASE_DIR / 'feature_names.pkl'
22
+
23
+
24
+ @st.cache_resource
25
+ def load_artifacts():
26
+ if not MODEL_PATH.exists():
27
+ raise FileNotFoundError(
28
+ f'Model not found: {MODEL_PATH.name}. Put it in the repo root (same folder as app.py).'
29
+ )
30
+ if not FEATURE_NAMES_PATH.exists():
31
+ raise FileNotFoundError(
32
+ f'Feature names not found: {FEATURE_NAMES_PATH.name}. Put it in the repo root (same folder as app.py).'
33
+ )
34
+
35
+ model = joblib.load(MODEL_PATH)
36
+ feature_names = joblib.load(FEATURE_NAMES_PATH)
37
+
38
+ if not isinstance(feature_names, list) or len(feature_names) == 0:
39
+ raise ValueError('feature_names.pkl must contain a non-empty list of column names.')
40
+
41
+ return model, feature_names
42
+
43
+
44
+ def add_features(df: pd.DataFrame) -> pd.DataFrame:
45
+ df = df.copy()
46
+
47
+ # Temperature variability
48
+ df['temp_range'] = df['maxtemp'] - df['mintemp']
49
+ # Air saturation level
50
+ df['humidity_gap'] = df['humidity'] - df['dewpoint']
51
+ # Sunshine vs clouds
52
+ df['sunshine_ratio'] = df['sunshine'] / (df['cloud'] + 1)
53
+ # Wind intensity (simple interaction)
54
+ df['wind_energy'] = df['windspeed'] * df['winddirection']
55
+ # Seasonal pattern
56
+ df['sin_day'] = np.sin(2 * np.pi * df['day'] / 365)
57
+ df['cos_day'] = np.cos(2 * np.pi * df['day'] / 365)
58
+
59
+ return df
60
+
61
+
62
+ model, feature_names = load_artifacts()
63
+
64
+ st.subheader('Input features')
65
+
66
+ # Note: ranges are generic. If you want, you can set them based on df1.describe().
67
+ col1, col2 = st.columns(2)
68
+
69
+ with col1:
70
+ day = st.number_input('day (1–365)', min_value=1, max_value=365, value=100, step=1)
71
+ pressure = st.number_input('pressure', value=1013.0, step=0.1)
72
+ maxtemp = st.number_input('maxtemp', value=20.0, step=0.1)
73
+ temperature = st.number_input('temperature', value=15.0, step=0.1)
74
+ mintemp = st.number_input('mintemp', value=10.0, step=0.1)
75
+
76
+ with col2:
77
+ dewpoint = st.number_input('dewpoint', value=8.0, step=0.1)
78
+ humidity = st.number_input('humidity', value=70.0, step=0.1)
79
+ cloud = st.number_input('cloud', value=50.0, step=1.0)
80
+ sunshine = st.number_input('sunshine', value=5.0, step=0.1)
81
+ windspeed = st.number_input('windspeed', value=10.0, step=0.1)
82
+ winddirection = st.number_input('winddirection', value=180.0, step=1.0)
83
+
84
+ # Build one-row dataframe with the ORIGINAL base features
85
+ input_df = pd.DataFrame([{
86
+ 'day': float(day),
87
+ 'pressure': float(pressure),
88
+ 'maxtemp': float(maxtemp),
89
+ 'temperature': float(temperature),
90
+ 'mintemp': float(mintemp),
91
+ 'dewpoint': float(dewpoint),
92
+ 'humidity': float(humidity),
93
+ 'cloud': float(cloud),
94
+ 'sunshine': float(sunshine),
95
+ 'windspeed': float(windspeed),
96
+ 'winddirection': float(winddirection)
97
+ }])
98
+
99
+
100
+ # Add engineered features (must match training)
101
+ input_df = add_features(input_df)
102
+
103
+ # Ensure correct feature order and missing columns safety
104
+ missing_cols = [c for c in feature_names if c not in input_df.columns]
105
+ extra_cols = [c for c in input_df.columns if c not in feature_names]
106
+
107
+ if missing_cols:
108
+ st.error(f'Missing required feature columns: {missing_cols}')
109
+ st.stop()
110
+
111
+ # Keep only the expected columns in the correct order
112
+ X = input_df[feature_names].copy()
113
+
114
+ st.divider()
115
+
116
+ if st.button('Predict rainfall probability'):
117
+ try:
118
+ proba = float(model.predict_proba(X)[:, 1][0])
119
+ st.metric('Rainfall probability', f'{proba:.3f}', delta=None)
120
+ st.progress(min(max(proba, 0.0), 1.0))
121
+
122
+ if proba >= 0.7:
123
+ st.success('High chance of rainfall.')
124
+ elif proba >= 0.4:
125
+ st.warning('Medium chance of rainfall.')
126
+ else:
127
+ st.info('Low chance of rainfall.')
128
+
129
+ with st.expander('Show model input (debug)'):
130
+ st.write('Used feature columns (ordered):')
131
+ st.write(feature_names)
132
+ st.dataframe(X)
133
+
134
+ if extra_cols:
135
+ st.caption(f'Note: These columns were ignored (not in feature_names): {extra_cols}')
136
+
137
+ except Exception as e:
138
+ st.error(f'Prediction failed: {e}')