Spaces:
Sleeping
Sleeping
import streamlit as st | |
import pandas as pd | |
import numpy as np | |
import joblib | |
from xgboost import XGBRegressor | |
from sklearn.preprocessing import StandardScaler, OneHotEncoder | |
import shap | |
from streamlit_shap import st_shap | |
# Page configuration | |
st.set_page_config( | |
page_title="Airbnb Price Prediction in Copenhagen", | |
page_icon="π ") | |
st.title('Predict Airbnb Prices in Copenhagen') | |
# Display an image | |
st.image('https://gdkfiles.visitdenmark.com/files/382/164757_Nyhavn_Jacob-Schjrring-og-Simon-Lau.jpg?width=987', caption='Copenhagen', use_column_width=True) | |
# Load model and preprocessing objects | |
def load_model_objects(): | |
model_xgb = joblib.load('model_xgb.joblib') | |
scaler = joblib.load('scaler.joblib') | |
ohe = joblib.load('ohe.joblib') | |
return model_xgb, scaler, ohe | |
model_xgb, scaler, ohe = load_model_objects() | |
# Create SHAP explainer | |
explainer = shap.TreeExplainer(model_xgb) | |
# App description | |
with st.expander("What's this app?"): | |
st.markdown(""" | |
This app helps you determine an appropriate nightly rate for your Airbnb listing in Copenhagen. | |
We've trained an AI model on successful listings in Copenhagen to provide pricing suggestions based on a few key inputs. | |
Our recommendation is to adjust the suggested price by about Β±350 DKK depending on your specific amenities and the quality of your place. | |
As a bonus feature π, we've included an AI explainer π€ to help you understand the factors influencing the predicted price. | |
""") | |
st.subheader('Describe your place') | |
# User inputs | |
col1, col2 = st.columns(2) | |
with col1: | |
n_hood = st.selectbox('Neighborhood', options=ohe.categories_[0]) | |
room_type = st.radio('Room Type', options=ohe.categories_[1]) | |
instant_bookable = st.checkbox('Instant Booking Available') | |
accommodates = st.number_input('Maximum Guests', min_value=1, max_value=16, value=2) | |
with col2: | |
bedrooms = st.number_input('Number of Bedrooms', min_value=0, max_value=10, value=1) | |
beds = st.number_input('Number of Beds', min_value=1, max_value=16, value=1) | |
min_nights = st.number_input('Minimum Nights Stay', min_value=1, max_value=30, value=1) | |
# Prediction button | |
if st.button('Predict Price π'): | |
# Prepare categorical features | |
cat_features = pd.DataFrame({'neighbourhood_cleansed': [n_hood], 'room_type': [room_type]}) | |
cat_encoded = pd.DataFrame(ohe.transform(cat_features).todense(), | |
columns=ohe.get_feature_names_out(['neighbourhood_cleansed', 'room_type'])) | |
# Prepare numerical features | |
num_features = pd.DataFrame({ | |
'instant_bookable': [instant_bookable], | |
'accommodates': [accommodates], | |
'bedrooms': [bedrooms], | |
'beds': [beds], | |
'minimum_nights_avg_ntm': [min_nights] | |
}) | |
num_scaled = pd.DataFrame(scaler.transform(num_features), columns=num_features.columns) | |
# Combine features | |
features = pd.concat([num_scaled, cat_encoded], axis=1) | |
# Make prediction | |
predicted_price = model_xgb.predict(features)[0] | |
# Display prediction | |
st.metric(label="Predicted price per night", value=f'{round(predicted_price)} DKK') | |
# Calculate and display price range | |
lower_range = max(0, round(predicted_price - 350)) | |
upper_range = round(predicted_price + 350) | |
st.write(f"Suggested price range: {lower_range} - {upper_range} DKK") | |
# SHAP explanation | |
st.subheader('Price Factors Explained π€') | |
shap_values = explainer.shap_values(features) | |
st_shap(shap.force_plot(explainer.expected_value, shap_values, features), height=400, width=600) | |
st.markdown(""" | |
This plot shows how each feature contributes to the predicted price: | |
- Blue bars push the price lower | |
- Red bars push the price higher | |
- The length of each bar indicates the strength of the feature's impact | |
""") | |
# Footer | |
st.markdown("---") | |
st.markdown("Developed with β€οΈ using Streamlit and AI") |