File size: 3,841 Bytes
b36eee9
 
 
 
 
 
 
 
 
0a14a79
b36eee9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
from pathlib import Path
import pickle

import gradio as gr
import pandas as pd


BASE_DIR = Path(__file__).resolve().parent
MODEL_PATH = BASE_DIR / "apartment_price_model.pkl"
DATA_PATH = BASE_DIR / "original_apartment_data_analytics_hs24.csv"


with MODEL_PATH.open("rb") as f:
    model = pickle.load(f)


df = pd.read_csv(DATA_PATH)
municipality_columns = ["town", "postalcode", "pop", "pop_dens", "frg_pct", "emp", "tax_income"]
municipality_df = df[municipality_columns].dropna().copy()
municipality_df["town"] = municipality_df["town"].astype(str).str.strip()
municipality_df = municipality_df.drop_duplicates(subset=["town"]).sort_values("town")
MUNICIPALITY_DATA = municipality_df.set_index("town").to_dict("index")


def _build_features(rooms: float, area: float, town: str) -> tuple[pd.DataFrame, dict]:
    municipality = MUNICIPALITY_DATA[town]

    pop = float(municipality["pop"])
    pop_dens = float(municipality["pop_dens"])
    frg_pct = float(municipality["frg_pct"])
    emp = float(municipality["emp"])
    tax_income = float(municipality["tax_income"])

    municipality_area_proxy = pop / pop_dens
    emp_per_resident = emp / pop
    foreigner_count_est = pop * (frg_pct / 100)

    features = pd.DataFrame(
        [
            {
                "rooms": rooms,
                "area": area,
                "pop": pop,
                "pop_dens": pop_dens,
                "frg_pct": frg_pct,
                "emp": emp,
                "tax_income": tax_income,
                "municipality_area_proxy": municipality_area_proxy,
                "emp_per_resident": emp_per_resident,
                "foreigner_count_est": foreigner_count_est,
            }
        ]
    )

    return features, municipality


def predict_price(rooms: float, area: float, town: str) -> tuple[str, str]:
    features, municipality = _build_features(rooms=rooms, area=area, town=town)
    prediction = float(model.predict(features)[0])

    pop = float(municipality["pop"])
    pop_dens = float(municipality["pop_dens"])
    frg_pct = float(municipality["frg_pct"])
    emp = float(municipality["emp"])
    
    municipality_area_proxy = pop / pop_dens
    emp_per_resident = emp / pop
    foreigner_count_est = pop * (frg_pct / 100)

    details = (
        f"Ort: {town} (PLZ {int(municipality['postalcode'])})\n\n"
        f"Gemeindedaten:\n"
        f"  Bevölkerung: {int(pop):,}\n"
        f"  Bevölkerungsdichte: {pop_dens:.1f}/km²\n"
        f"  Ausländeranteil: {frg_pct:.1f}%\n"
        f"  Beschäftigte: {int(emp):,}\n"
        f"  Steuerbares Einkommen: CHF {municipality['tax_income']:,.0f}\n\n"
        f"Zusätzliche berechnete Features:\n"
        f"  Gemeindegröße: {municipality_area_proxy:.2f} km²\n"
        f"  Arbeitsplatzquote: {emp_per_resident:.3f}\n"
        f"  Ausländerpopulation: {int(foreigner_count_est):,}"
    )

    return f"CHF {prediction:,.2f} pro Monat", details


demo = gr.Interface(
    fn=predict_price,
    inputs=[
        gr.Slider(1, 8, value=3, step=0.5, label="Zimmer"),
        gr.Slider(20, 250, value=80, step=1, label="Wohnfläche (m²)"),
        gr.Dropdown(choices=list(MUNICIPALITY_DATA.keys()), value="Zürich", label="Gemeinde"),
    ],
    outputs=[
        gr.Textbox(label="Geschätzte Miete"),
        gr.Textbox(label="Verwendete Gemeindedaten"),
    ],
    examples=[
        [2.5, 60, "Zürich"],
        [3.5, 90, "Winterthur"],
        [4.5, 120, "Uster"],
    ],
    title="Apartment Price Prediction – Kanton Zürich",
    description=(
        "Vorhersage der monatlichen Wohnungsmiete mit einem Random-Forest-Regressionsmodell. "
        "Die App nutzt Basismerkmale und zusätzliche Feature-Engineering-Variablen "
        "(municipality_area_proxy, emp_per_resident, foreigner_count_est)."
    ),
)


if __name__ == "__main__":
    demo.launch()