Spaces:
Paused
Paused
| import os | |
| import joblib | |
| import numpy as np | |
| import pandas as pd | |
| import streamlit as st | |
| st.set_page_config(page_title="Quality & Price Prediction", page_icon="💎", layout="wide") | |
| ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | |
| def load_models(): | |
| return { | |
| "wine": joblib.load(os.path.join(ROOT, "wine_model.pkl")), | |
| "wine_columns": joblib.load(os.path.join(ROOT, "feature_columns.pkl")), | |
| "diamond": joblib.load(os.path.join(ROOT, "diamond_bundle.pkl")), | |
| "tips": joblib.load(os.path.join(ROOT, "waiter_tip_bundle.joblib")), | |
| } | |
| models = load_models() | |
| st.title("💎 Quality & Price Prediction Hub") | |
| st.caption("Three trained regression and classification projects with practical input forms.") | |
| wine_tab, diamond_tab, tip_tab = st.tabs(["Wine Quality", "Diamond Price", "Waiter Tip"]) | |
| with wine_tab: | |
| st.subheader("Predict wine quality from laboratory measurements") | |
| a, b, c = st.columns(3) | |
| wine_values = { | |
| "fixed acidity": a.number_input("Fixed acidity", 3.0, 20.0, 8.0, .1), | |
| "volatile acidity": a.number_input("Volatile acidity", 0.0, 2.0, .5, .01), | |
| "citric acid": a.number_input("Citric acid", 0.0, 2.0, .3, .01), | |
| "residual sugar": a.number_input("Residual sugar", 0.0, 70.0, 2.5, .1), | |
| "chlorides": b.number_input("Chlorides", 0.0, 1.0, .08, .005, format="%.3f"), | |
| "free sulfur dioxide": b.number_input("Free sulfur dioxide", 0.0, 300.0, 15.0, 1.0), | |
| "total sulfur dioxide": b.number_input("Total sulfur dioxide", 0.0, 500.0, 46.0, 1.0), | |
| "density": b.number_input("Density", .98, 1.05, .9968, .0001, format="%.4f"), | |
| "pH": c.number_input("pH", 2.0, 5.0, 3.3, .01), | |
| "sulphates": c.number_input("Sulphates", 0.0, 3.0, .65, .01), | |
| "alcohol": c.number_input("Alcohol (%)", 5.0, 25.0, 10.5, .1), | |
| } | |
| if st.button("Predict wine quality", type="primary"): | |
| row = pd.DataFrame([{**{"Id": 0}, **wine_values}]).reindex(columns=models["wine_columns"], fill_value=0) | |
| quality = int(models["wine"].predict(row)[0]) | |
| st.metric("Predicted quality", f"{quality} / 10") | |
| st.success("High-quality profile") if quality >= 7 else st.info("Typical-quality profile" if quality >= 5 else "Lower-quality profile") | |
| with diamond_tab: | |
| st.subheader("Estimate a diamond's price in US dollars") | |
| cut_map = {"Fair": 1, "Good": 2, "Very Good": 3, "Premium": 4, "Ideal": 5} | |
| color_map = {"J": 1, "I": 2, "H": 3, "G": 4, "F": 5, "E": 6, "D": 7} | |
| clarity_map = {"I1": 1, "SI2": 2, "SI1": 3, "VS2": 4, "VS1": 5, "VVS2": 6, "VVS1": 7, "IF": 8} | |
| a, b, c = st.columns(3) | |
| carat = a.number_input("Carat", .1, 6.0, 1.0, .05) | |
| depth = a.number_input("Depth (%)", 40.0, 80.0, 61.5, .1) | |
| table = a.number_input("Table (%)", 40.0, 100.0, 57.0, .1) | |
| x = b.number_input("Length x (mm)", 1.0, 15.0, 6.4, .1) | |
| y = b.number_input("Width y (mm)", 1.0, 15.0, 6.4, .1) | |
| z = b.number_input("Depth z (mm)", .5, 10.0, 4.0, .1) | |
| cut = c.selectbox("Cut", list(cut_map), index=4) | |
| color = c.selectbox("Color", list(color_map), index=3) | |
| clarity = c.selectbox("Clarity", list(clarity_map), index=3) | |
| if st.button("Estimate diamond price", type="primary"): | |
| values = {"carat": carat, "depth": depth, "table": table, "x": x, "y": y, "z": z, "volume": x*y*z, "color_ord": color_map[color], "clarity_ord": clarity_map[clarity], "cut_ord": cut_map[cut]} | |
| row = pd.DataFrame([values], columns=models["diamond"]["columns"]) | |
| price = max(0.0, float(models["diamond"]["model"].predict(row)[0])) | |
| st.metric("Estimated price", f"${price:,.0f}") | |
| st.caption("Educational estimate based on the training dataset; laboratory certification and market conditions also affect real prices.") | |
| with tip_tab: | |
| st.subheader("Estimate a restaurant tip") | |
| a, b = st.columns(2) | |
| bill = a.number_input("Total bill ($)", 1.0, 500.0, 35.0, 1.0) | |
| party = a.slider("Party size", 1, 10, 2) | |
| sex = a.selectbox("Customer sex (dataset field)", ["Female", "Male"]) | |
| smoker = b.selectbox("Smoking table", ["No", "Yes"]) | |
| day = b.selectbox("Day", ["Thursday", "Friday", "Saturday", "Sunday"]) | |
| meal = b.selectbox("Meal", ["Dinner", "Lunch"]) | |
| if st.button("Estimate tip", type="primary"): | |
| day_code = {"Friday": 0, "Saturday": 1, "Sunday": 2, "Thursday": 3}[day] | |
| weekend = int(day in ["Friday", "Saturday", "Sunday"]) | |
| smoker_code = int(smoker == "Yes") | |
| values = {"total_bill": bill, "sex": int(sex == "Male"), "smoker": smoker_code, "day": day_code, "time": int(meal == "Lunch"), "size": party, "is_weekend": weekend, "is_smoker": smoker_code, "is_dinner": int(meal == "Dinner"), "bill_x_size": bill*party, "smoker_weekend": smoker_code*weekend} | |
| row = pd.DataFrame([values], columns=models["tips"]["features"]) | |
| tip = max(0.0, float(models["tips"]["model"].predict(row)[0])) | |
| st.metric("Estimated tip", f"${tip:.2f}", f"{tip/bill:.1%} of bill") | |
| st.caption("Model validation MAE: approximately $0.75 on the small 244-row tips dataset.") | |
| st.divider() | |
| st.caption("Portfolio of Jale Summak · Educational machine-learning estimates") | |