Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import pandas as pd | |
| import numpy as np | |
| import matplotlib.pyplot as plt | |
| import seaborn as sns | |
| from sklearn.linear_model import LinearRegression | |
| from sklearn.model_selection import train_test_split | |
| from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score | |
| from statsmodels.stats.outliers_influence import variance_inflation_factor | |
| from sklearn.datasets import fetch_california_housing | |
| from sklearn.model_selection import cross_validate | |
| import time | |
| from sklearn.model_selection import learning_curve | |
| def show_intro(): | |
| with st.expander(f"➡️ What is Regression?"): | |
| st.markdown(""" | |
| **Regression** is a fundamental statistical technique used to understand and quantify the relationship between a **dependent variable (what you want to predict)** and one or more **independent variables (predictors)**. | |
| --- | |
| ###### 🔍 Everyday Examples of Regression: | |
| - 📈 Predicting **house prices** based on size, location, and number of bedrooms. | |
| - 🎓 Estimating a student’s **final grade** based on hours of study and attendance. | |
| - 🚗 Forecasting **fuel efficiency** based on engine size and weight of the car. | |
| - 🧠 Predicting **IQ scores** or **height** based on parental traits (enter Galton! 👇) | |
| --- | |
| ###### 👨👩👧👦 Galton’s Theory – *Regression to the Mean* | |
| Sir Francis Galton, a 19th-century statistician and cousin of Charles Darwin, studied the heights of parents and their children. | |
| He observed: | |
| - Very tall parents tended to have children **shorter** than themselves. | |
| - Very short parents tended to have children **taller** than themselves. | |
| 🧠 He coined the term **"regression to the mean"**, which means: | |
| > "Extreme traits tend to be followed by traits closer to the average in the next generation." | |
| --- | |
| ###### 👶 Real-Life Example: | |
| - If both parents are exceptionally tall (say, 6'5"), their child is **likely tall**, but **closer to the average height** than the parents — maybe 6'2". | |
| - Similarly, if parents are very short, the child’s height tends to “regress” toward the average population height. | |
| This pattern **doesn't mean height is random**, just that genetics and environment **pull traits toward typical values** over time. | |
| --- | |
| Regression models in ML extend this idea — instead of modeling parent-child height, we model **any continuous outcome** based on relevant input variables. | |
| """) | |
| with st.expander("➡️ Industry Use-Cases of Regression Models"): | |
| st.markdown(""" | |
| ###### 🏥 Healthcare | |
| - 🔬 Estimating **patient recovery time** based on age, treatment type, and initial condition. | |
| - 💉 Predicting **blood glucose levels** based on dietary habits and medication dosage. | |
| - 🫀 Forecasting **hospital readmission rates** based on prior health records and discharge details. | |
| ###### 🛒 Retail | |
| - 📦 Predicting **sales volume** based on pricing, seasonality, and promotional campaigns. | |
| - 🛍️ Estimating **inventory demand** for specific SKUs using historical sales and trends. | |
| - 👗 Forecasting **customer churn** likelihood using past purchase behavior and returns. | |
| ###### 🛍️ E-commerce | |
| - 💸 Predicting **customer lifetime value (CLV)** based on purchase frequency and basket size. | |
| - 🚚 Estimating **delivery time** based on warehouse location, item type, and order volume. | |
| - 🧾 Forecasting **return probability** of products based on description, images, and reviews. | |
| ###### 💰 Finance | |
| - 📊 Predicting **stock prices** or **bond yields** based on historical trends and market indicators. | |
| - 🏦 Estimating **credit risk** or **loan default probability** using income, credit history, etc. | |
| - 💳 Forecasting **spending patterns** on credit cards based on customer behavior. | |
| ###### 💊 Pharma & Life Sciences | |
| - 🧪 Predicting **drug efficacy** based on dosage and patient demographics in clinical trials. | |
| - 🦠 Estimating **disease progression** timelines based on early symptoms and test results. | |
| - 💊 Forecasting **adverse drug reactions** from formulation and patient profiles. | |
| """) | |
| def simple_regression_example(): | |
| with st.expander("➡️ Single Variable Regression (Manual Calculation)"): | |
| # Sample data | |
| advertising_spend = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) | |
| sales_revenue = np.array([2.1, 3.9, 5.2, 6.0, 7.1, 8.1, 9.0, 10.2, 10.8, 12.0]) | |
| # Regression coefficients (manual calculation) | |
| x_mean = np.mean(advertising_spend) | |
| y_mean = np.mean(sales_revenue) | |
| b1 = np.sum((advertising_spend - x_mean) * (sales_revenue - y_mean)) / np.sum((advertising_spend - x_mean)**2) | |
| b0 = y_mean - b1 * x_mean | |
| predicted_sales = b0 + b1 * advertising_spend | |
| # Two-column layout | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| st.markdown("###### 📊 Sample Data") | |
| df = pd.DataFrame({ | |
| 'Advertising Spend (in lakhs)': advertising_spend, | |
| 'Sales Revenue (in lakhs)': sales_revenue | |
| }) | |
| st.dataframe(df) | |
| with col2: | |
| st.markdown("###### 📉 Linear Regression Formula") | |
| st.markdown(f""" | |
| The linear regression equation is: | |
| **Sales Revenue = {b0:.2f} + {b1:.2f} × Advertising Spend** | |
| Where: | |
| - **b₀ (Intercept)**: Sales revenue when advertising spend is zero. | |
| - **b₁ (Slope)**: Increase in revenue for each additional lakh spent. | |
| ###### Formula for Computing Coefficients | |
| - **b₁ (Slope)** = (Σ(xᵢ - x̄)(yᵢ - ȳ)) / Σ(xᵢ - x̄)² | |
| - **b₀ (Intercept)** = ȳ - b₁ × x̄ | |
| """) | |
| # Plotting the regression line | |
| fig, ax = plt.subplots(figsize=(9,4)) | |
| ax.scatter(advertising_spend, sales_revenue, color='blue', label='Actual') | |
| ax.plot(advertising_spend, predicted_sales, color='red', label='Fitted Line') | |
| ax.set_xlabel("Advertising Spend (in lakhs)", fontsize=10) | |
| ax.set_ylabel("Sales Revenue (in lakhs)", fontsize=10) | |
| ax.set_title("Linear Regression: Advertising Spend vs Sales Revenue", fontsize=10) | |
| ax.tick_params(axis='both', labelsize=8) | |
| ax.legend() | |
| st.pyplot(fig) | |
| with st.expander("➡️ Predict Sales Revenue from Advertising Spend"): | |
| st.markdown(f"Use the trained regression model to forecast expected sales revenue 📈") | |
| user_input = st.number_input( | |
| "Enter Advertising Spend (in lakhs)", | |
| min_value=1.0, | |
| max_value=20.0, | |
| value=5.0, | |
| step=0.5, | |
| format="%.1f" | |
| ) | |
| if user_input: | |
| predicted_value = b0 + b1 * user_input | |
| st.success(f"🔮 Predicted Sales Revenue: **{predicted_value:.2f} lakhs**") | |
| # Visualize prediction on the regression chart | |
| fig, ax = plt.subplots(figsize=(9,4)) | |
| ax.scatter(advertising_spend, sales_revenue, color='blue', label='Actual') | |
| ax.plot(advertising_spend, predicted_sales, color='red', label='Fitted Line') | |
| # Add dashed lines for prediction | |
| ax.axvline(x=user_input, color='red', linestyle='--', linewidth=1) | |
| ax.axhline(y=predicted_value, color='red', linestyle='--', linewidth=1) | |
| ax.plot(user_input, predicted_value, 'ro') # predicted point | |
| ax.set_xlabel("Advertising Spend (in lakhs)", fontsize=10) | |
| ax.set_ylabel("Sales Revenue (in lakhs)", fontsize=10) | |
| ax.set_title("Prediction on Regression Line", fontsize=10) | |
| ax.tick_params(axis='both', labelsize=8) | |
| ax.legend() | |
| st.pyplot(fig) | |
| with st.expander("➡️ Key Takeaways ..."): | |
| st.markdown(""" | |
| - 🔍 **Simplicity with Impact**: Even a simple linear model offers valuable foresight—linking investments (like ad spend) directly to outcomes (like sales revenue). | |
| - 📊 **Data-Driven Decisions**: Enables leadership to make **objective** decisions, backed by quantitative evidence rather than gut feel. | |
| - 🎯 **Budget Optimization**: Helps identify how much to invest to hit revenue targets—minimizing under or over-spending on campaigns. | |
| - 📈 **Trend Insights**: Understanding whether returns from increased spending are **linear**, diminishing, or plateauing over time. | |
| - 🧪 **Foundation for More Advanced Models**: This simple regression builds the base for multivariable models involving seasonality, regions, or digital channels. | |
| """) | |
| def load_ca_data(): | |
| data = fetch_california_housing(as_frame=True) | |
| X = data.frame.drop(['MedHouseVal'], axis=1) | |
| y = data.frame['MedHouseVal'] | |
| return data.frame, X,y | |
| def vif_check(df): | |
| X = df.drop(columns=['MedHouseVal']) | |
| vif_data = pd.DataFrame() | |
| vif_data["feature"] = X.columns | |
| vif_data["VIF"] = [variance_inflation_factor(X.values, i) for i in range(X.shape[1])] | |
| return vif_data, X, df['MedHouseVal'] | |
| def build_model(X_train, y_train): | |
| model = LinearRegression() | |
| model.fit(X_train, y_train) | |
| return model | |
| def main(): | |
| st.markdown(f"**🧠 Regression Intuitions - Linear Regression Demo**") | |
| show_intro() | |
| simple_regression_example() | |
| with st.expander("➡️ Load & View California Housing Dataset"): | |
| df, X, y = load_ca_data() | |
| st.dataframe(df.head()) | |
| st.markdown(""" | |
| The **California Housing Dataset** is based on data from the 1990 U.S. Census. | |
| It contains information collected from block groups across California and is often used for regression tasks to predict housing values. | |
| ###### 📌 Columns Description: | |
| - **MedInc** *(Median Income)*: Median income of households in the block group (in tens of thousands of dollars). | |
| - **HouseAge** *(Median House Age)*: Median age of houses in the area. | |
| - **AveRooms** *(Average Rooms)*: Average number of rooms per household. | |
| - **AveBedrms** *(Average Bedrooms)*: Average number of bedrooms per household. | |
| - **Population**: Total population of the block group. | |
| - **AveOccup** *(Average Occupancy)*: Average number of people per household. | |
| - **Latitude**: Geographical latitude of the block group. | |
| - **Longitude**: Geographical longitude of the block group. | |
| ###### 🎯 Target Column: | |
| - **MedHouseVal** *(Median House Value)*: This is the target variable to be predicted. | |
| It represents the **median house value** in the block group (in hundreds of thousands of dollars). | |
| """) | |
| st.markdown("###### 🗺️ California Housing: Prices by Location") | |
| fig, ax = plt.subplots(figsize=(12, 5)) | |
| scatter = ax.scatter( | |
| df["Longitude"], | |
| df["Latitude"], | |
| c=df["MedHouseVal"], | |
| cmap="viridis", | |
| s=10, | |
| alpha=0.5 | |
| ) | |
| ax.set_title("Median House Value across California", fontsize=14) | |
| ax.set_xlabel("Longitude") | |
| ax.set_ylabel("Latitude") | |
| ax.grid(True) | |
| # Add color bar to represent house value | |
| cbar = plt.colorbar(scatter, ax=ax) | |
| cbar.set_label("Median House Value ($100,000s)") | |
| # Annotate major cities | |
| ax.annotate("Los Angeles", xy=(-118.25, 34.05), xytext=(-121, 33.8), | |
| arrowprops=dict(facecolor='red', arrowstyle="->"), fontsize=10, color='red') | |
| ax.annotate("San Francisco", xy=(-122.42, 37.77), xytext=(-125, 38.5), | |
| arrowprops=dict(facecolor='blue', arrowstyle="->"), fontsize=10, color='blue') | |
| # Shade ocean region (rough approximation: west of longitude -123) | |
| ax.axvspan(-125, -123, color='lightblue', alpha=0.3, label="Pacific Ocean") | |
| # Add legend | |
| ax.legend(loc="lower right") | |
| st.pyplot(fig) | |
| st.write(f""" | |
| - Color represents housing value: darker → cheaper, lighter → more expensive. | |
| - notice high-value clusters around coastal regions (e.g., around the Bay Area and Los Angeles). | |
| """ | |
| ) | |
| with st.expander("➡️ Key Challenges of California Housing Dataset (Regression vs Rule-Based Models)"): | |
| st.markdown(""" | |
| Understanding the limitations of both data and modeling approaches is vital for leaders making data-driven decisions. Below are the key challenges when using this dataset for **regression modeling**, especially compared to traditional **rule-based systems**: | |
| ###### 🔍 Data Challenges (Specific to Regression): | |
| - **Non-linear Relationships**: Housing prices may not increase proportionally with income, age, or other features, making simple linear models insufficient. | |
| - **Geographic Bias**: Locations like LA and SF have unique dynamics not captured by standard features—housing is expensive due to factors beyond income or age. | |
| - **Data Outliers**: Some neighborhoods may have unusually high or low prices, skewing the model's predictions. | |
| - **Capped Target Values**: The `MedHouseVal` was capped at $500,000 in the dataset, which can limit the model's ability to predict higher-end housing. | |
| ###### 🤖 Compared to Rule-Based Models: | |
| - **Rule-based systems lack adaptability**: Rules like "if income > X, price > Y" cannot account for regional nuances, housing density, or socio-economic patterns. | |
| - **Hard to scale**: Adding new rules for every edge case becomes complex and unmanageable over time. | |
| - **Not data-driven**: Rule-based logic does not improve from historical data or learn from new patterns. | |
| ###### 🧭 Key Takeaway: | |
| > Regression models offer adaptability and learning from patterns across vast geographies and populations. However, they require clean, unbiased data and continuous validation—unlike rule-based systems, which are simple but brittle and not future-proof. | |
| """) | |
| # with st.expander("➡️Linearity Check & VIF"): | |
| # vif_data, X, y = vif_check(df) | |
| # st.dataframe(vif_data) | |
| with st.expander("➡️ Prepare Data for the regression model"): | |
| st.markdown(""" | |
| Creating training and test datasets is a fundamental step in building machine learning models. It ensures the model learns patterns **only from part of the data**, and is then **evaluated on unseen data** to measure its performance. | |
| ###### 🔧 Why Prepare Data? | |
| - **Ensures Model Quality**: Models need structured and clean data to learn effectively. | |
| - **Prevents Overfitting**: By separating training from testing, we prevent the model from simply memorizing the data. | |
| - **Enables Generalization**: A well-prepared dataset ensures the model can make accurate predictions on new, real-world data. | |
| ###### 📦 Train-Test Split | |
| - **Training Set**: Used by the model to learn patterns and relationships between input (features) and output (target). | |
| - **Test Set**: Held back during training and used solely to evaluate model performance. It simulates how the model would perform in production. | |
| ###### ✅ Best Practices | |
| - **Use an 80/20 or 70/30 split** depending on dataset size. | |
| - **Stratify** if your target variable is imbalanced (more applicable in classification). | |
| - **Set a random seed** (e.g., `random_state=42`) for reproducibility. | |
| - **Clean and preprocess** before splitting to avoid data leakage. | |
| - **Avoid using test data during model training or tuning**—this ensures an unbiased evaluation. | |
| > 🔍 **Key point**: Proper data preparation is like setting the foundation of a building—without it, even the most advanced models can crumble in production. | |
| """) | |
| X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) | |
| # Display the number of samples in training and testing sets | |
| st.write(f"Number of samples in training set: {X_train.shape[0]}") | |
| st.write(f"Number of samples in testing set: {X_test.shape[0]}") | |
| st.write("Train and test sets created.") | |
| with st.expander("➡️ Build Linear Regression Model"): | |
| #model = build_model(X_train, y_train) | |
| st.write("Training the Linear Regression model...") | |
| # Simulate training with progress bar | |
| progress_bar = st.progress(0) | |
| for i in range(100): | |
| time.sleep(0.01) | |
| progress_bar.progress(i + 1) | |
| # Train the model | |
| model = LinearRegression() | |
| model.fit(X_train, y_train) | |
| st.success("Model trained successfully.") | |
| # Predict and compute metrics | |
| y_pred = model.predict(X_test) | |
| mae = mean_absolute_error(y_test, y_pred) | |
| mse = mean_squared_error(y_test, y_pred) | |
| rmse = np.sqrt(mse) | |
| r2 = r2_score(y_test, y_pred) | |
| st.markdown("###### 📊 Model Evaluation on Test Set") | |
| st.write(f"**MAE**: {mae:.2f}") | |
| st.write(f"**MSE**: {mse:.2f}") | |
| st.write(f"**RMSE**: {rmse:.2f}") | |
| st.write(f"**R² Score**: {r2:.2f}") | |
| # Cross-validation to detect overfitting | |
| st.markdown("###### 🔁 Cross-Validation Performance") | |
| cv_results = cross_validate(model, X, y, cv=10, return_train_score=True, scoring='r2') | |
| train_r2 = cv_results['train_score'] | |
| test_r2 = cv_results['test_score'] | |
| r2_df = pd.DataFrame({ | |
| 'Fold': list(range(1, 11)), | |
| 'Training R²': train_r2, | |
| 'Test R²': test_r2 | |
| }) | |
| fig, ax = plt.subplots(figsize=(9,5)) | |
| ax.plot(r2_df['Fold'], r2_df['Training R²'], marker='o', label='Training R²', color='blue') | |
| ax.plot(r2_df['Fold'], r2_df['Test R²'], marker='o', label='Test R²', color='green') | |
| ax.set_title("Cross-Validation R² Scores") | |
| ax.set_xlabel("Fold") | |
| ax.set_ylabel("R² Score") | |
| ax.legend() | |
| ax.grid(True) | |
| st.pyplot(fig) | |
| st.dataframe(r2_df.style.format({'Training R²': '{:.2f}', 'Test R²': '{:.2f}'})) | |
| st.write(""" | |
| - ✅ **Consistent Training Performance**: | |
| The training R² scores range from **0.59 to 0.63**, indicating a fairly **consistent learning pattern** across all 10 folds. | |
| This means the model generalizes reasonably well on the training data. | |
| - ⚠️ **Test Set Variability**: | |
| The test R² scores range from **0.42 to 0.61**, showing **slightly higher variance** across folds. | |
| Some folds show strong performance (e.g., Fold 2), while others drop noticeably (e.g., Fold 3). | |
| - 🔁 **No Severe Overfitting Detected**: | |
| If the training R² was very high (e.g., 0.9) and test R² was low (e.g., 0.3), that would indicate **overfitting**. | |
| In this case, **training and test R² are fairly close**, suggesting the model is **not overfitting significantly**. | |
| - 📉 **Room for Improvement**: | |
| An average test R² around **0.52** implies that the model explains **just over 50% of the variance** in house values. | |
| For business-critical applications like real estate pricing or policy decisions, we may consider: | |
| - **Feature engineering** (e.g., regional segmentation), | |
| - **Model tuning**, or | |
| - **Trying more expressive models** like decision trees or gradient boosting. | |
| """) | |
| # learning curve | |
| with st.expander("➡️ Was Training Data Sufficient? (Learning Curve Analysis)"): | |
| st.markdown("###### 📊 Learning Curve Analysis") | |
| # Generate learning curves | |
| train_sizes, train_scores, test_scores = learning_curve( | |
| model, X, y, cv=5, scoring='r2', train_sizes=np.linspace(0.1, 1.0, 10), shuffle=True, random_state=42 | |
| ) | |
| # Calculate mean and std deviation | |
| train_scores_mean = np.mean(train_scores, axis=1) | |
| test_scores_mean = np.mean(test_scores, axis=1) | |
| # Plotting | |
| fig, ax = plt.subplots(figsize=(9,4)) | |
| ax.plot(train_sizes, train_scores_mean, 'o-', color="blue", label="Training R²") | |
| ax.plot(train_sizes, test_scores_mean, 'o-', color="green", label="Validation R²") | |
| ax.set_title("Learning Curve: Linear Regression") | |
| ax.set_xlabel("Number of Training Samples") | |
| ax.set_ylabel("R² Score") | |
| ax.legend(loc="best") | |
| ax.grid(True) | |
| st.pyplot(fig) | |
| # Interpret results | |
| st.write(""" | |
| - ✅ **Training R² is high initially** (indicating the model learns patterns even with fewer samples). | |
| - 📉 **Validation R² improves as training size increases**, then plateaus. | |
| - 🧠 This suggests the model **benefits from more training data**, but after a certain point, **additional data does not significantly improve generalization**. | |
| - 🔍 The **gap between training and validation curves** is relatively small, indicating **no severe overfitting**. | |
| - 📌 **Conclusion**: The current dataset size seems **adequate**, and the model is learning well with the data provided. | |
| """) | |
| with st.expander("📊 Understand Feature Impact: Coefficients of the Linear Regression Model"): | |
| importance = model.coef_ | |
| features = X.columns | |
| fig, ax = plt.subplots(figsize=(9,5)) | |
| ax.barh(features, importance, color='skyblue') | |
| ax.set_title("Feature Importance (Linear Regression Coefficients)") | |
| ax.set_xlabel("Coefficient Value") | |
| st.pyplot(fig) | |
| st.markdown(""" | |
| ###### 🔍 Interpretation: | |
| - Features with larger **absolute values** have a stronger effect on the predicted house value. | |
| - A **positive coefficient** increases the predicted value. | |
| - A **negative coefficient** decreases the predicted value. | |
| ###### 🧠 What it means for decision-makers: | |
| - **Median Income** is a strong positive driver — wealthier areas tend to have higher housing values. | |
| - **Latitude** has a negative coefficient — northern areas may have lower house prices. | |
| - Helps focus strategic decisions on what really influences prices across California. | |
| """) | |
| with st.expander("🧠 Why Linear Regression Still Matters: Foundation for Deep Learning & Transformers"): | |
| st.markdown(""" | |
| Linear Regression may look simple, but it's far from trivial — it’s the **first building block** in the ladder to advanced AI models like **Deep Learning** and **Transformers**. | |
| ###### 📚 Conceptual Foundations: | |
| - **Weights & Bias**: The core of linear regression is about learning weights and biases — which is exactly what **every neural network layer** does, just at scale. | |
| - **Loss Minimization**: Linear regression minimizes **Mean Squared Error** — a principle used in training neural networks to adjust weights through **backpropagation**. | |
| - **Linear Combinations**: Deep learning models, at their core, are just multiple layers of **linear transformations + non-linear activations**. | |
| ###### 🤖 Connect to Transformers: | |
| - Transformer architectures (like GPT, BERT) use **linear projections** in attention mechanisms. | |
| - Every layer in these models performs matrix multiplications — which is, again, just advanced **linear algebra and regression-like operations**. | |
| ###### 🏗️ Strategic Insight: | |
| - A solid grasp of linear regression builds the intuition needed to understand more complex systems. | |
| - Senior leaders can better evaluate ML and AI project feasibility and interpret outcomes by understanding these **fundamentals that scale**. | |
| 🔄 *"From Linear Regression to Transformers, it's all about modeling relationships and optimizing parameters — just with different levels of complexity and abstraction."* | |
| """) | |
| if __name__ == "__main__": | |
| main() | |