fusin001 commited on
Commit
71b2e85
·
verified ·
1 Parent(s): 236445a

Upload folder using huggingface_hub

Browse files
Files changed (2) hide show
  1. README.md +33 -0
  2. app.py +23 -17
README.md CHANGED
@@ -80,6 +80,39 @@ Reduce overfitting, improve generalization with richer features and better hyper
80
 
81
  All three models achieve ~0.70 R². RF train/test gap reduced to ~0.10 (was ~0.32). Good Fit.
82
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  ---
84
 
85
  ## New Feature: `income_density_score`
 
80
 
81
  All three models achieve ~0.70 R². RF train/test gap reduced to ~0.10 (was ~0.32). Good Fit.
82
 
83
+ ## Iteration 3 Room Scaling and Correct Defaults
84
+ Fix the prediction plateau and improve scaling across all room counts and price ranges.
85
+
86
+ **Steps:**
87
+ - Added log_rooms
88
+ - Added area_rooms_interact = area × rooms
89
+ - Corrected pop_dens defaults in the app: `4,729` for Zurich City, `1,328` for outside (both derived from training data medians)
90
+
91
+ **Models and Hyperparameters:**
92
+ - Ridge(alpha=10.0)
93
+ - RandomForestRegressor(n_estimators=300, max_depth=15, min_samples_leaf=3, random_state=42)
94
+ - GradientBoostingRegressor(n_estimators=800, max_depth=5, learning_rate=0.03, min_samples_leaf=3, subsample=0.8, random_state=42)
95
+
96
+ **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)`
97
+
98
+ **Results:**
99
+
100
+ | Model | CV R² | CV Std |
101
+ |-------|--------|--------|
102
+ | Ridge (alpha=10) | 0.72 | 0.04 |
103
+ | Random Forest (tuned) | 0.72 | 0.05 |
104
+ | Gradient Boosting (tuned) | 0.72 | 0.05 |
105
+
106
+ Example predictions after fix (Zurich City, Kreis 3):
107
+
108
+ | Rooms | Area | Predicted Rent |
109
+ |-------|------|----------------|
110
+ | 1.0 | 30 m² | CHF 1,157 |
111
+ | 3.0 | 80 m² | CHF 3,121 |
112
+ | 4.5 | 115 m² | CHF 3,741 |
113
+ | 5.5 | 145 m² | CHF 4,972 |
114
+ | 6.5 | 175 m² | CHF 5,879 |
115
+
116
  ---
117
 
118
  ## New Feature: `income_density_score`
app.py CHANGED
@@ -13,11 +13,13 @@ model = model_data["model"]
13
  features = model_data["features"]
14
  log_target = model_data["log_target"]
15
 
16
- # Default values for removed inputs
17
- DEFAULT_POP_DENS = 1500.0
18
- DEFAULT_FRG_PCT = 25.0
19
- DEFAULT_LAT = 47.38
20
- DEFAULT_LON = 8.54
 
 
21
 
22
 
23
  def predict_price(
@@ -26,19 +28,21 @@ def predict_price(
26
  attika, loft, seesicht,
27
  kreis
28
  ):
29
- # Use defaults for hidden features
30
- pop_dens = DEFAULT_POP_DENS
31
- frg_pct = DEFAULT_FRG_PCT
32
- lat = DEFAULT_LAT
33
- lon = DEFAULT_LON
34
 
35
  # Derived features
36
- log_area = np.log1p(area)
37
- log_rooms = np.log1p(rooms)
38
- rooms_area_ratio = rooms / (area + 1)
39
- room_per_m2 = area / rooms if rooms > 0 else area
40
  income_density_score = tax_income * pop_dens / 1e6
41
- area_rooms_interact = area * rooms
 
 
42
 
43
  # Kreis dummies
44
  kreis_cols = {f"Kreis {i}": 0 for i in range(1, 13)}
@@ -51,9 +55,11 @@ def predict_price(
51
  "log_area": log_area,
52
  "log_rooms": log_rooms,
53
  "pop_dens": pop_dens,
 
54
  "frg_pct": frg_pct,
55
  "tax_income": tax_income,
56
  "income_density_score": income_density_score,
 
57
  "rooms_area_ratio": rooms_area_ratio,
58
  "area_rooms_interact": area_rooms_interact,
59
  "lat": lat,
@@ -108,7 +114,7 @@ demo = gr.Interface(
108
  title="Zurich Apartment Rent Predictor",
109
  description=(
110
  "Predict the monthly rental price for an apartment in the Canton of Zurich.\n\n"
111
- "This model uses a **Random Forest Regressor** trained on ~800 Zurich apartment listings, "
112
  "with features including location (district), apartment characteristics, "
113
  "and the **Income-Density Score** (a neighbourhood affluence proxy)."
114
  ),
@@ -116,4 +122,4 @@ demo = gr.Interface(
116
  )
117
 
118
  if __name__ == "__main__":
119
- demo.launch()
 
13
  features = model_data["features"]
14
  log_target = model_data["log_target"]
15
 
16
+ DEFAULT_POP_DENS_CITY = 4729.0
17
+ DEFAULT_POP_DENS_OUTSIDE = 1328.0
18
+ DEFAULT_FRG_PCT = 25.0
19
+ DEFAULT_LAT_CITY = 47.380402
20
+ DEFAULT_LON_CITY = 8.530496
21
+ DEFAULT_LAT_OUTSIDE = 47.424900
22
+ DEFAULT_LON_OUTSIDE = 8.638663
23
 
24
 
25
  def predict_price(
 
28
  attika, loft, seesicht,
29
  kreis
30
  ):
31
+ # Use data-derived defaults for hidden features
32
+ pop_dens = DEFAULT_POP_DENS_CITY if zurich_city else DEFAULT_POP_DENS_OUTSIDE
33
+ lat = DEFAULT_LAT_CITY if zurich_city else DEFAULT_LAT_OUTSIDE
34
+ lon = DEFAULT_LON_CITY if zurich_city else DEFAULT_LON_OUTSIDE
35
+ frg_pct = DEFAULT_FRG_PCT
36
 
37
  # Derived features
38
+ log_area = np.log1p(area)
39
+ log_rooms = np.log1p(rooms)
40
+ rooms_area_ratio = rooms / (area + 1)
41
+ room_per_m2 = area / rooms if rooms > 0 else area
42
  income_density_score = tax_income * pop_dens / 1e6
43
+ log_income_dens = np.log1p(income_density_score)
44
+ log_pop_dens = np.log1p(pop_dens)
45
+ area_rooms_interact = area * rooms
46
 
47
  # Kreis dummies
48
  kreis_cols = {f"Kreis {i}": 0 for i in range(1, 13)}
 
55
  "log_area": log_area,
56
  "log_rooms": log_rooms,
57
  "pop_dens": pop_dens,
58
+ "log_pop_dens": log_pop_dens,
59
  "frg_pct": frg_pct,
60
  "tax_income": tax_income,
61
  "income_density_score": income_density_score,
62
+ "log_income_dens": log_income_dens,
63
  "rooms_area_ratio": rooms_area_ratio,
64
  "area_rooms_interact": area_rooms_interact,
65
  "lat": lat,
 
114
  title="Zurich Apartment Rent Predictor",
115
  description=(
116
  "Predict the monthly rental price for an apartment in the Canton of Zurich.\n\n"
117
+ "This model uses a **Gradient Boosting Regressor** trained on ~800 Zurich apartment listings, "
118
  "with features including location (district), apartment characteristics, "
119
  "and the **Income-Density Score** (a neighbourhood affluence proxy)."
120
  ),
 
122
  )
123
 
124
  if __name__ == "__main__":
125
+ demo.launch()