File size: 7,399 Bytes
209940a 4b0cd04 209940a 50fd5d6 209940a 50fd5d6 209940a 4b0cd04 209940a 4b0cd04 209940a 4b0cd04 209940a 4b0cd04 209940a 4b0cd04 209940a 50fd5d6 209940a 4b0cd04 209940a 50fd5d6 19d68d1 50fd5d6 4b0cd04 50fd5d6 4b0cd04 50fd5d6 19d68d1 50fd5d6 19d68d1 50fd5d6 19d68d1 50fd5d6 19d68d1 50fd5d6 209940a |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
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() |