CoolFace
Apppublic

nanthsar/Apartmant_Price_Zurich

sourceHugging Faceupdated 7mo agoView on Hugging Face
0likes
App README

Apartment Price Prediction - Canton of Zurich

This app predicts the monthly rental price of apartments in the canton of Zurich using a machine learning model.

Project Overview

ItemDetail
TaskRegression - predict monthly rent in CHF
Dataset~800 apartment listings from the canton of Zurich
Final ModelGradient Boosting Regressor
Final CV RMSE~610 CHF
Final CV R²0.63

Preprocessing Steps

  1. 1.Removed outliers: kept apartments with price between CHF 750 and CHF 8,000
  2. 2.Dropped rows with missing values
  3. 3.Added existing features from the lecture: roomperm2, area categories, luxury flags, Zurich Kreis encoding, furnished and temporary flags
  4. 4.Added my own new features (see below)

New Features

1. Distance to Zurich city center (dist_to_zurich_center) I calculated the distance in km from each apartment to Zurich city center using the Haversine formula. The GPS coordinates were already in the dataset from the GeoAdmin API. Apartments closer to the city center are usually more expensive.

2. Outdoor space (aussenbereich) I searched the apartment descriptions for keywords like balcony, terrace and loggia. In the data I saw that apartments that explicitly mention a balcony are on average a little cheaper. This might be because expensive apartments have one without mentioning it.

3. Price categories (UX improvement) I added a price category to make the app more user-friendly. Based on the price distribution in the dataset I defined three categories:

  • —🟢 Affordable (under CHF 1,800)
  • —🟡 Mid-range (CHF 1,800 - 3,000)
  • —🔴 Expensive (above CHF 3,000)

Iterative Modeling Process

Iteration 1 - Baseline

Objective: Start with simple features to establish a baseline.

Preprocessing steps:

  • —Removed outliers (price < CHF 750 or > CHF 8,000)
  • —Dropped rows with missing values
  • —Used basic numeric features only

Features: rooms, area, pop, popdens, frgpct, emp, taxincome, roomperm2, areacatecoded, zurichcity

ModelHyperparametersMean CV RMSEMean CV R²Std Dev R²Fit Diagnosis
Linear Regressiondefault-710 CHF0.480.107☑ Slight Overfitting
Random Forestdefault (n_estimators=100)-709 CHF0.510.060☑ Overfitting

Finding: Both models perform similarly. R² of ~0.50 means the model explains only 50% of the price variance. I decided to add more features and try a stronger model.


Iteration 2 - Extended Features + Tuning

Objective: Improve performance by adding more features and trying a stronger model.

Preprocessing steps (changes vs. Iteration 1):

  • —Added luxury flags from description: ATTIKA, LOFT, SEESICHT, LUXURIÖS, POOL, EXKLUSIV
  • —Added furnished and temporary binary flags
  • —Added Zurich Kreis one-hot encoding (Kreis 1-12)
  • —Added new feature: disttozurich_center (Haversine distance in km)
  • —Added new feature: aussenbereich (balcony/terrace/loggia from description)
  • —Tuned Random Forest hyperparameters
  • —Added Gradient Boosting as second model
ModelHyperparametersMean CV RMSEMean CV R²Std Dev R²Fit Diagnosis
Random Forest (tuned)nestimators=500, minsamplesleaf=2, minsamples_split=5-631 CHF0.600.071☑ Overfitting
Gradient Boostingnestimators=300, learningrate=0.05, max_depth=4-610 CHF0.630.053☑ Overfitting

Finding: Gradient Boosting performed best with R²=0.63 and the lowest std dev (0.053), meaning it is the most stable model. The RMSE improved by ~100 CHF compared to the baseline. All tree-based models show overfitting (high train R² vs lower CV R²), which is typical for these model types. Cross-validation ensures the reported CV performance is still reliable on unseen data. All tree-based models show overfitting (high train R² vs lower CV R²), which is typical for Random Forest and Gradient Boosting. Cross-validation ensures the reported performance is still reliable on unseen data.


Evaluation Method

  • —5-fold Cross-Validation
  • —Metrics: RMSE (Root Mean Squared Error) in CHF and R² (coefficient of determination)
  • —Lower RMSE = better | Higher R² = better (max 1.0)
  • —R² of 0.63 means the model explains 63% of the price variance

Final Model

Gradient Boosting Regressor - chosen because it achieved the best CV RMSE (-610 CHF) and highest R² (0.63) with the lowest standard deviation.

  • —n_estimators = 300
  • —learning_rate = 0.05
  • —max_depth = 4
  • —random_state = 42

Files

FileDescription
app.pyGradio web application
train_model.pyModel training script
model.pklTrained model
features.pklFeature list used during training
town_stats.csvTown statistics for lookup
requirements.txtPython dependencies

References

  • —Geron, A. (2019). Hands-On Machine Learning with Scikit-Learn and TensorFlow. O'Reilly.
  • —https://scikit-learn.org/
  • —https://www.gradio.app/guides/quickstart
  • —https://huggingface.co/docs/hub/en/spaces-sdks-gradio