Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import pandas as pd | |
| import numpy as np | |
| from sklearn.model_selection import train_test_split | |
| from sklearn.preprocessing import StandardScaler | |
| from sklearn.ensemble import RandomForestClassifier | |
| from sklearn.metrics import accuracy_score | |
| # -------------------------- Page Config -------------------------- | |
| st.set_page_config( | |
| page_title="Wine Quality Master π·", | |
| page_icon="π", | |
| layout="centered", | |
| initial_sidebar_state="expanded" | |
| ) | |
| # -------------------------- Custom CSS - Dark Purple Magic -------------------------- | |
| st.markdown(""" | |
| <style> | |
| .main {background: #0f001a; color: #e6e6fa;} | |
| .stApp {background: linear-gradient(135deg, #2a0052, #000000);} | |
| h1, h2 {background: linear-gradient(90deg, #9b59b6, #e91e63, #ff9800); | |
| -webkit-background-clip: text; -webkit-text-fill-color: transparent;} | |
| .wine-red {color: #c0392b;} | |
| .wine-white {color: #f1c40f;} | |
| .prediction-good {font-size: 2.5rem; font-weight: bold; text-align: center; | |
| color: #8e44ad; text-shadow: 0 0 20px #9b59b6;} | |
| </style> | |
| """, unsafe_allow_html=True) | |
| # -------------------------- Load Full Wine Quality Dataset (Red + White) -------------------------- | |
| def load_wine_data(): | |
| # Red wine | |
| red = pd.read_csv("https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv", sep=";") | |
| red["type"] = "Red" | |
| # White wine | |
| white = pd.read_csv("https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-white.csv", sep=";") | |
| white["type"] = "White" | |
| # Combine | |
| df = pd.concat([red, white], ignore_index=True) | |
| # Binary classification: Good (>=6), Bad (<6) | |
| df["is_good"] = (df["quality"] >= 6).astype(int) | |
| return df | |
| df = load_wine_data() | |
| # -------------------------- Hero Section -------------------------- | |
| col1, col2, col3 = st.columns([1,3,1]) | |
| with col2: | |
| st.markdown("<h1 style='text-align:center;'>Wine Quality Master</h1>", unsafe_allow_html=True) | |
| st.markdown("<h2 style='text-align:center;'>VinoVerdict</h2>", unsafe_allow_html=True) | |
| st.markdown("<p style='text-align:center; font-size:1.4rem; opacity:0.9;'>Red or White β Will it be divine... or declined?</p>", unsafe_allow_html=True) | |
| st.markdown("---") | |
| # -------------------------- Dataset Info -------------------------- | |
| with st.container(): | |
| st.markdown("<div class='glass-card'>", unsafe_allow_html=True) | |
| col1, col2, col3, col4 = st.columns(4) | |
| with col1: | |
| st.metric("Total Wines", f"{len(df):,}") | |
| with col2: | |
| st.metric("Red Wines", f"{len(df[df['type']=='Red']):,}", "Red Wine") | |
| with col3: | |
| st.metric("White Wines", f"{len(df[df['type']=='White']):,}", "White Wine") | |
| with col4: | |
| st.metric("Good Wines (β₯6)", f"{df['is_good'].sum():,}") | |
| st.markdown("<br>", unsafe_allow_html=True) | |
| st.dataframe(df.head(), use_container_width=True) | |
| st.markdown("</div>", unsafe_allow_html=True) | |
| # -------------------------- Prepare Features -------------------------- | |
| X = df.drop(columns=["quality", "is_good"]) | |
| y = df["is_good"] | |
| # One-hot encode wine type (ensures consistent column order) | |
| X = pd.get_dummies(X, columns=["type"], drop_first=False) | |
| # Train-test split | |
| X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y) | |
| # Scale numerical features (preserve exact column order) | |
| scaler = StandardScaler() | |
| numerical_cols = [col for col in X.columns if col not in ["type_Red", "type_White"]] | |
| X_train_num_scaled = scaler.fit_transform(X_train[numerical_cols]) | |
| X_train = pd.concat([ | |
| pd.DataFrame(X_train_num_scaled, columns=numerical_cols, index=X_train.index), | |
| X_train[["type_Red", "type_White"]] | |
| ], axis=1) | |
| X_test_num_scaled = scaler.transform(X_test[numerical_cols]) | |
| X_test = pd.concat([ | |
| pd.DataFrame(X_test_num_scaled, columns=numerical_cols, index=X_test.index), | |
| X_test[["type_Red", "type_White"]] | |
| ], axis=1) | |
| # Train model | |
| def train_model(): | |
| model = RandomForestClassifier( | |
| n_estimators=1000, | |
| max_depth=15, | |
| random_state=42, | |
| n_jobs=-1, | |
| class_weight="balanced" | |
| ) | |
| model.fit(X_train, y_train) | |
| return model | |
| model = train_model() | |
| # Accuracy | |
| y_pred = model.predict(X_test) | |
| accuracy = accuracy_score(y_test, y_pred) | |
| with st.container(): | |
| st.markdown("<div class='glass-card'>", unsafe_allow_html=True) | |
| st.success(f"Model Accuracy on Test Set: *{accuracy:.4f}* ({accuracy*100:.2f}%)") | |
| st.markdown("</div>", unsafe_allow_html=True) | |
| # -------------------------- Interactive Prediction -------------------------- | |
| st.markdown("<div class='glass-card'>", unsafe_allow_html=True) | |
| st.header("Predict Your Wine's Destiny") | |
| # Wine type selector | |
| wine_type = st.selectbox("Choose Wine Type", options=["Red", "White"], index=0) | |
| col1, col2 = st.columns(2) | |
| input_data = {"type_Red": 0, "type_White": 0} | |
| input_data[f"type_{wine_type}"] = 1 | |
| features = [col for col in X.columns if col not in ["type_Red", "type_White"]] | |
| for i, feature in enumerate(features): | |
| col = col1 if i % 2 == 0 else col2 | |
| with col: | |
| min_v, max_v = float(df[feature].min()), float(df[feature].max()) | |
| mean_v = float(df[feature].mean()) | |
| val = st.slider( | |
| feature.replace("_", " ").title(), | |
| min_value=min_v, | |
| max_value=max_v, | |
| value=mean_v, | |
| step=0.1, | |
| format="%.2f" | |
| ) | |
| input_data[feature] = val | |
| if st.button("Reveal the Quality!", use_container_width=True, type="primary"): | |
| input_df = pd.DataFrame([input_data]) | |
| # Scale numerical columns (FIX: Reconstruct to match exact column order) | |
| input_num_scaled = scaler.transform(input_df[numerical_cols]) | |
| input_scaled = pd.concat([ | |
| pd.DataFrame(input_num_scaled, columns=numerical_cols, index=input_df.index), | |
| input_df[["type_Red", "type_White"]] | |
| ], axis=1) | |
| pred = model.predict(input_scaled)[0] | |
| prob = model.predict_proba(input_scaled)[0] | |
| st.markdown("<br>", unsafe_allow_html=True) | |
| if pred == 1: | |
| st.balloons() | |
| st.markdown(f"<h2 class='prediction-good'>OUTSTANDING WINE! {wine_type} Wine</h2>", unsafe_allow_html=True) | |
| st.success(f"Confidence: *{prob[1]:.1%}* β This belongs in a museum... or your glass right now!") | |
| else: | |
| st.error(f"Not quite a masterpiece... {wine_type} Wine") | |
| st.warning(f"Confidence: *{prob[0]:.1%}* β Maybe use it for cooking?") | |
| # Feature importance hint | |
| st.info(f"Pro tip: For {wine_type.lower()} wines, alcohol, sulphates, and volatile acidity matter most!") | |
| st.markdown("</div>", unsafe_allow_html=True) | |
| # -------------------------- Footer -------------------------- | |
| st.markdown("---") | |
| st.caption("Made with passion | Dataset: UCI Wine Quality (Red + White) | Model: Random Forest |Created by: MAN JETANI") | |