--- title: Application1 emoji: 🐠 colorFrom: yellow colorTo: purple sdk: gradio sdk_version: "6.9.0" app_file: app.py pinned: false short_description: Appartement price prediction --- # Zurich Apartment Rent Predictor This application predicts monthly rental prices (CHF) for apartments in the Canton of Zurich. **Live App:** TODOOOOOOOOO[Hugging Face Spaces – Zurich Apartment Predictor](#) ## Model Iterations ### Summary Table | Iteration | Objective | Key Changes | Models Used | CV Mean R² | CV Std | Δ Performance | Fit Diagnosis | |-----------|-----------|-------------|-------------|------------|--------|----------------|---------------| | **1** | Baseline | Basic cleaning, no log transform, 9 features, default hyperparameters | Linear Regression, Random Forest (n=100) | 0.61 (RF) / 0.60 (LR) | 0.10 / 0.06 | Baseline | Overfitting (RF) | | **2** | Improve generalization | Log-transform target, 32 features incl. income_density_score (new), lat/lon, Kreis dummies, tuned hyperparameters | Ridge (α=10), RF (n=300, depth=15), Gradient Boosting | 0.70 | 0.04–0.07 | +0.09 | Good Fit | ### Iteration 1 Baseline Establish a performance baseline. **Steps:** - Loaded `apartments_data_enriched_with_new_features.csv` - Dropped rows with missing values in selected columns - Used raw (untransformed) price as target - Evaluated with 5-fold cross-validation (`KFold`, `shuffle=True`, `random_state=42`) **Models and Hyperparameters:** - LinearRegression - RandomForestRegressor(n_estimators=100, random_state=42) **Features:** `rooms, area, pop_dens, frg_pct, tax_income, luxurious, furnished, temporary, zurich_city` **Results:** | Model | CV R² | CV Std | CV RMSE (CHF) | |-------|--------|--------|----------------| | Linear Regression | 0.60 | 0.06 | ~679 | | Random Forest | 0.61 | 0.10 | ~666 | Random Forest shows large gap between train R² (~0.93) and test R² (~0.61) → Linear model underfits. Both need improvement. --- ### Iteration 2 Improved Model Reduce overfitting, improve generalization with richer features and better hyperparameters. **Steps:** - Log-transform target variable to reduce right skew and improve linear model performance - Engineered new feature: income_density_score = (tax_income × pop_dens) / 1,000,000 - Engineered additional features: log_area, rooms_area_ratio - Added geographic features: `lat`, `lon` - Added Zurich district dummies: `Kreis 1–12` - Added keyword flags from listing text: (LOFT),(SEESICHT), etc. **Models and Hyperparameters:** - Ridge(alpha=10.0) - RandomForestRegressor(n_estimators=300, max_depth=15, min_samples_leaf=3, random_state=42) - GradientBoostingRegressor(n_estimators=300, max_depth=5, learning_rate=0.05, random_state=42) **Features:** `rooms, area, log_area, pop_dens, frg_pct, tax_income, income_density_score, rooms_area_ratio, lat, lon, luxurious, furnished, temporary, zurich_city, room_per_m2, Kreis 1–12, (ATTIKA), (LOFT), (SEESICHT), (LUXURIÖS), (POOL), (EXKLUSIV)` **Results:** | Model | CV R² | CV Std | |-------|--------|--------| | Ridge (alpha=10) | 0.70 | 0.04 | | Random Forest (tuned) | 0.70 | 0.07 | | Gradient Boosting | 0.70 | 0.07 | All three models achieve ~0.70 R². RF train/test gap reduced to ~0.10 (was ~0.32). Good Fit. ## Iteration 3 Room Scaling and Correct Defaults Fix the prediction plateau and improve scaling across all room counts and price ranges. **Steps:** - Added log_rooms - Added area_rooms_interact = area × rooms - Corrected pop_dens defaults in the app: `4,729` for Zurich City, `1,328` for outside (both derived from training data medians) **Models and Hyperparameters:** - Ridge(alpha=10.0) - RandomForestRegressor(n_estimators=300, max_depth=15, min_samples_leaf=3, random_state=42) - GradientBoostingRegressor(n_estimators=800, max_depth=5, learning_rate=0.03, min_samples_leaf=3, subsample=0.8, random_state=42) **Features:** `rooms, area, log_area, log_rooms, pop_dens, log_pop_dens, frg_pct, tax_income, income_density_score, log_income_dens, rooms_area_ratio, area_rooms_interact, lat, lon, luxurious, furnished, temporary, zurich_city, room_per_m2, Kreis 1–12, (ATTIKA), (LOFT), (SEESICHT), (LUXURIÖS), (POOL), (EXKLUSIV)` **Results:** | Model | CV R² | CV Std | |-------|--------|--------| | Ridge (alpha=10) | 0.72 | 0.04 | | Random Forest (tuned) | 0.72 | 0.05 | | Gradient Boosting (tuned) | 0.72 | 0.05 | Example predictions after fix (Zurich City, Kreis 3): | Rooms | Area | Predicted Rent | |-------|------|----------------| | 1.0 | 30 m² | CHF 1,157 | | 3.0 | 80 m² | CHF 3,121 | | 4.5 | 115 m² | CHF 3,741 | | 5.5 | 145 m² | CHF 4,972 | | 6.5 | 175 m² | CHF 5,879 | --- ## New Feature: `income_density_score` income_density_score = (tax_income × pop_dens) / 1,000,000 This feature combines municipal tax income with population density to create a neighbourhood affluence proxy. A dense area with high-income residents (for example Kreis 1 or Küsnacht) will score much higher than a sparse rural municipality. ## Final Selected Model **Model:** `RandomForestRegressor(n_estimators=300, max_depth=15, min_samples_leaf=3)` **Target:** `log(1 + price)` → predictions are back-transformed with `expm1()` **CV R²:** 0.70 | **CV Std:** 0.07 **Evaluation:** 5-fold cross-validation **Top Feature Importances:** 1. `log_area` — log-transformed living area 2. `area` — living area in m² 3. `rooms` — number of rooms 4. `income_density_score` (new feature) 5. `lat` — latitude (geographic location)