| import numpy as np |
| import pandas as pd |
| import streamlit as st |
| import joblib |
| from pathlib import Path |
|
|
| |
| |
| |
| st.set_page_config( |
| page_title='Rainfall Probability Predictor (LogReg)', |
| page_icon='🌧️', |
| layout='centered' |
| ) |
|
|
| st.title('🌧️ Rainfall Probability Predictor') |
| st.write('Predicts the probability of rainfall (0–1) using a Logistic Regression model trained on weather features.') |
|
|
| BASE_DIR = Path(__file__).resolve().parent |
| MODEL_PATH = BASE_DIR / 'lr_final_model.pkl' |
| FEATURE_NAMES_PATH = BASE_DIR / 'feature_names.pkl' |
|
|
|
|
| @st.cache_resource |
| def load_artifacts(): |
| if not MODEL_PATH.exists(): |
| raise FileNotFoundError( |
| f'Model not found: {MODEL_PATH.name}. Put it in the repo root (same folder as app.py).' |
| ) |
| if not FEATURE_NAMES_PATH.exists(): |
| raise FileNotFoundError( |
| f'Feature names not found: {FEATURE_NAMES_PATH.name}. Put it in the repo root (same folder as app.py).' |
| ) |
|
|
| model = joblib.load(MODEL_PATH) |
| feature_names = joblib.load(FEATURE_NAMES_PATH) |
|
|
| if not isinstance(feature_names, list) or len(feature_names) == 0: |
| raise ValueError('feature_names.pkl must contain a non-empty list of column names.') |
|
|
| return model, feature_names |
|
|
|
|
| def add_features(df: pd.DataFrame) -> pd.DataFrame: |
| df = df.copy() |
|
|
| |
| df['temp_range'] = df['maxtemp'] - df['mintemp'] |
| |
| df['humidity_gap'] = df['humidity'] - df['dewpoint'] |
| |
| df['sunshine_ratio'] = df['sunshine'] / (df['cloud'] + 1) |
| |
| df['wind_energy'] = df['windspeed'] * df['winddirection'] |
| |
| df['sin_day'] = np.sin(2 * np.pi * df['day'] / 365) |
| df['cos_day'] = np.cos(2 * np.pi * df['day'] / 365) |
|
|
| return df |
|
|
|
|
| model, feature_names = load_artifacts() |
|
|
| st.subheader('Input features') |
|
|
| |
| col1, col2 = st.columns(2) |
|
|
| with col1: |
| day = st.number_input('day (1–365)', min_value=1, max_value=365, value=100, step=1) |
| pressure = st.number_input('pressure', value=1013.0, step=0.1) |
| maxtemp = st.number_input('maxtemp', value=20.0, step=0.1) |
| temperature = st.number_input('temperature', value=15.0, step=0.1) |
| mintemp = st.number_input('mintemp', value=10.0, step=0.1) |
|
|
| with col2: |
| dewpoint = st.number_input('dewpoint', value=8.0, step=0.1) |
| humidity = st.number_input('humidity', value=70.0, step=0.1) |
| cloud = st.number_input('cloud', value=50.0, step=1.0) |
| sunshine = st.number_input('sunshine', value=5.0, step=0.1) |
| windspeed = st.number_input('windspeed', value=10.0, step=0.1) |
| winddirection = st.number_input('winddirection', value=180.0, step=1.0) |
|
|
| |
| input_df = pd.DataFrame([{ |
| 'day': float(day), |
| 'pressure': float(pressure), |
| 'maxtemp': float(maxtemp), |
| 'temparature': float(temperature), |
| 'mintemp': float(mintemp), |
| 'dewpoint': float(dewpoint), |
| 'humidity': float(humidity), |
| 'cloud': float(cloud), |
| 'sunshine': float(sunshine), |
| 'windspeed': float(windspeed), |
| 'winddirection': float(winddirection) |
| }]) |
|
|
|
|
| |
| input_df = add_features(input_df) |
|
|
| |
| missing_cols = [c for c in feature_names if c not in input_df.columns] |
| extra_cols = [c for c in input_df.columns if c not in feature_names] |
|
|
| if missing_cols: |
| st.error(f'Missing required feature columns: {missing_cols}') |
| st.stop() |
|
|
| |
| X = input_df[feature_names].copy() |
|
|
| st.divider() |
|
|
| if st.button('Predict rainfall probability'): |
| try: |
| proba = float(model.predict_proba(X)[:, 1][0]) |
| st.metric('Rainfall probability', f'{proba:.3f}', delta=None) |
| st.progress(min(max(proba, 0.0), 1.0)) |
|
|
| if proba >= 0.7: |
| st.success('High chance of rainfall.') |
| elif proba >= 0.4: |
| st.warning('Medium chance of rainfall.') |
| else: |
| st.info('Low chance of rainfall.') |
|
|
| with st.expander('Show model input (debug)'): |
| st.write('Used feature columns (ordered):') |
| st.write(feature_names) |
| st.dataframe(X) |
|
|
| if extra_cols: |
| st.caption(f'Note: These columns were ignored (not in feature_names): {extra_cols}') |
|
|
| except Exception as e: |
| st.error(f'Prediction failed: {e}') |