exercise1 / app.py
chrisis2's picture
Upload app.py
19d68d1 verified
import gradio as gr
import pandas as pd
import numpy as np
import pickle
from math import radians, cos, sin, asin, sqrt
# Load the model
with open("apartment_price_model.pkl", mode="rb") as f:
model = pickle.load(f)
# Define Zurich neighborhoods with their approximate coordinates and distances
zurich_neighborhoods = {
"City Center (Altstadt)": {"lat": 47.3769, "lon": 8.5417, "distance": 0.0},
"Oerlikon": {"lat": 47.4111, "lon": 8.5458, "distance": 3.8},
"Altstetten": {"lat": 47.3908, "lon": 8.4889, "distance": 4.2},
"Wiedikon": {"lat": 47.3708, "lon": 8.5128, "distance": 2.3},
"Seefeld": {"lat": 47.3550, "lon": 8.5550, "distance": 2.7},
"Schwamendingen": {"lat": 47.4053, "lon": 8.5648, "distance": 3.5},
"Wollishofen": {"lat": 47.3517, "lon": 8.5304, "distance": 3.0},
"Enge": {"lat": 47.3656, "lon": 8.5267, "distance": 1.2},
"Fluntern": {"lat": 47.3797, "lon": 8.5611, "distance": 1.8},
"Hottingen": {"lat": 47.3683, "lon": 8.5584, "distance": 1.5},
"Custom Location": {"lat": 47.3769, "lon": 8.5417, "distance": 0.0}
}
# Function to calculate distance between two points using Haversine formula
def haversine_distance(lat1, lon1, lat2, lon2):
"""Calculate the great circle distance between two points on earth."""
# Convert decimal degrees to radians
lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])
# Haversine formula
dlon = lon2 - lon1
dlat = lat2 - lat1
a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
c = 2 * asin(sqrt(a))
r = 6371 # Radius of earth in kilometers
return c * r
def predict_price(neighborhood, rooms, area, has_balcony, is_renovated, custom_lat=None, custom_lon=None):
# Get coordinates based on neighborhood selection
if neighborhood == "Custom Location" and custom_lat is not None and custom_lon is not None:
lat = custom_lat
lon = custom_lon
else:
lat = zurich_neighborhoods[neighborhood]["lat"]
lon = zurich_neighborhoods[neighborhood]["lon"]
# Calculate distance to city center
zurich_center_lat = zurich_neighborhoods["City Center (Altstadt)"]["lat"]
zurich_center_lon = zurich_neighborhoods["City Center (Altstadt)"]["lon"]
if neighborhood == "Custom Location" and custom_lat is not None and custom_lon is not None:
distance_to_center = haversine_distance(custom_lat, custom_lon, zurich_center_lat, zurich_center_lon)
else:
distance_to_center = zurich_neighborhoods[neighborhood]["distance"]
# Default values for other features
pop = 420217
pop_dens = 4778
frg_pct = 32.45
emp = 491193
tax_income = 85446
price_per_room = 0 # This will be updated by the model
# Create input dataframe
input_data = pd.DataFrame([{
'rooms': rooms,
'area': area,
'pop': pop,
'pop_dens': pop_dens,
'frg_pct': frg_pct,
'emp': emp,
'tax_income': tax_income,
'price_per_room': price_per_room,
'distance_to_center': distance_to_center,
'has_balcony': 1 if has_balcony else 0,
'is_renovated': 1 if is_renovated else 0
}])
# Define features in the correct order
features = [
'rooms', 'area', 'pop', 'pop_dens', 'frg_pct', 'emp', 'tax_income',
'price_per_room', 'distance_to_center', 'has_balcony', 'is_renovated'
]
# Make prediction
predicted_price = model.predict(input_data[features])[0]
# Format the result
result = f"Predicted Monthly Rent: CHF {predicted_price:.0f}"
result += f"\n\nProperty Details:"
result += f"\n- Location: {neighborhood}"
result += f"\n- {rooms} rooms, {area} m²"
result += f"\n- {distance_to_center:.2f} km from city center"
result += f"\n- {'Has balcony' if has_balcony else 'No balcony'}"
result += f"\n- {'Renovated' if is_renovated else 'Not renovated'}"
return result
# Function to update visibility of lat/lon inputs based on neighborhood selection
def update_custom_location(neighborhood):
if neighborhood == "Custom Location":
return gr.update(visible=True), gr.update(visible=True)
else:
return gr.update(visible=False), gr.update(visible=False)
# Function to reset all inputs to default values
def reset_inputs():
return [
"City Center (Altstadt)", # neighborhood
47.3769, # custom_lat
8.5417, # custom_lon
3.5, # rooms
75, # area
True, # has_balcony
False, # is_renovated
"" # clear output
]
# Create Gradio interface with neighborhood dropdown
with gr.Blocks() as demo:
gr.Markdown("# Zurich Apartment Rent Prediction")
gr.Markdown("""
This app predicts apartment rental prices in Zurich with a special feature: Distance to City Center.
**Special Feature Description:**
The model automatically calculates how far the apartment is from Zurich city center.
This distance is a critical factor in real estate pricing - properties closer to the city center typically
command higher rents due to convenience and accessibility to urban amenities.
Simply select a neighborhood, and the app will use its distance from the city center to help
provide a more accurate rental price prediction.
""")
with gr.Row():
with gr.Column():
neighborhood = gr.Dropdown(
label="Neighborhood",
choices=list(zurich_neighborhoods.keys()),
value="City Center (Altstadt)"
)
custom_lat = gr.Number(label="Custom Latitude", value=47.3769, visible=False)
custom_lon = gr.Number(label="Custom Longitude", value=8.5417, visible=False)
rooms = gr.Number(label="Number of Rooms", value=3.5)
area = gr.Number(label="Area (m²)", value=75)
has_balcony = gr.Checkbox(label="Has Balcony", value=True)
is_renovated = gr.Checkbox(label="Is Renovated", value=False)
with gr.Row():
submit_button = gr.Button("Submit")
clear_button = gr.Button("Clear")
with gr.Column():
output = gr.Textbox(label="Output")
# Connect the neighborhood dropdown to show/hide custom lat/lon
neighborhood.change(
fn=update_custom_location,
inputs=neighborhood,
outputs=[custom_lat, custom_lon]
)
# Connect the submit button
submit_button.click(
fn=predict_price,
inputs=[neighborhood, rooms, area, has_balcony, is_renovated, custom_lat, custom_lon],
outputs=output
)
# Connect the clear button
clear_button.click(
fn=reset_inputs,
inputs=None,
outputs=[neighborhood, custom_lat, custom_lon, rooms, area, has_balcony, is_renovated, output]
)
# Add examples
gr.Examples(
examples=[
["Oerlikon", 3.5, 75, True, True],
["Seefeld", 2.0, 60, False, False],
["Wiedikon", 4.5, 120, True, False],
],
inputs=[neighborhood, rooms, area, has_balcony, is_renovated],
outputs=output,
fn=predict_price
)
demo.launch()