Skip to content

CzechAI Cenové Mapy — Kompletní Historie a Aktuální Stav

Dokument je plně self-contained. Žádné externí file reference. Stav ke: 2026-05-04 Zdroje: live SSH server 179/94, PM2, Outline záloha 211 MB, MAPA_KOMPLETNI_DESKTOP (2026-03-07, 9 273 řádků kódu)


PŘEHLED VÝVOJE (chronologická tabulka)

Datum Fáze Co vzniklo Port Stav
2025-11 0 Scraping: ULTIMATE_MASTER.db (98K inzerátů) archív
2025-12 1a Statistická mapa — cenova_mapa.py + HOT tagy 5088 archív
2025-12 1a overnight_price_scraper — nočně aktualizovaná data archív
2026-01-14 1b Cenová Kalkulačka 2025 — web frontend na router.czechai.io archív
2026-01 2 Mapa 1 — Prodeje V4: 105K+ inzerátů, cascade lookup 5091 deprecated
2026-01 2 Mapa 2 — CSU V4: krajské mediány + sezónní koeficient 5092 deprecated
2026-01 2 Mapa 3 — AI V7: XGB+LGB+GBR, 225K záznamů, BYT MdAPE 7.6% 5093 deprecated
2026-02 2 Mapa 4 — Smart Engine: 13 podtypů, MAD outlier, taxonomie 5098 deprecated
2026-02 2 Mapa 5 — Fusion Engine: 4 DB zdroje (CUZK/CSU/LIVE/stat) 5094 deprecated
2026-02 3 Super Maps: Precision/Conservative/Ensemble/Unified 7001–7003,7000 stopped
2026-02 3 Oceňovač GPS/KNN: 145K záznamů, haversine 5300 stopped
2026-02 3 Valuo proxy engines (5 proxies → 7000) 6000–6100 stopped
2026-03 3 Super-Ensemble V2: FastAPI, 7 enginů paralelně, LLM review 5111 stopped
2026-03 3 Znalecký Panel: 3 AI znalci (qwen3:32b) + Chairman 5112 stopped
2026-03 3 Market Intel, Mapa Levon, CSU Engine, Smart Router 5400,6200,5102,5150 stopped
2026-03-07 MAPA_KOMPLETNI_DESKTOP doc: 28 služeb, 9 273 ř. kódu archív
2026-03-10 4 Perfect Map V13: HistGBM + meta-learner, R²=0.833, 296K zázn. 5131 deprecated
2026-04 5 V15: dedikovaný ML model (fallback) 5150 záloha
2026-04-24 6 V24: LGB+XGB+RF+KNN, 34 feature, BYT R²=0.9478 5164 PRODUKCE
2026-04-24 6 Combo3 router: byt/dům→V24, ostatní→V15 5163 PRODUKCE
2026-05-03 7 shadow.czechai.io + EstateX Council + Direct CMA public PRODUKCE

1. Proč vznikly cenové mapy

Celý projekt začal jako potřeba automaticky oceňovat nemovitosti z realitních inzerátů. Scraper na serverech 134 a 179 stahoval stovky tisíc inzerátů ze Sreality, Bezrealitky, Bazoše a dalších portálů — ale bez referenčního oceňovacího modelu nebylo možné rozpoznat, které inzeráty jsou předražené a které jsou podhodnocené příležitosti.

Cíl byl vždy stejný: dát každé nemovitosti tržní cenu na základě polohy, plochy a typu, a říct o kolik procent se inzerát odchyluje od trhu.

Z toho vznikl systém D-tagů: - D10 / D15 / D20 / D30 = podhodnoceno o 10/15/20/30+ % - FAIR = tržní cena - P10 / P20+ = nadhodnoceno


2. Fáze 1a — Statistická mapa (2025-12, port 5088)

Co to bylo

První Python skript cenova_mapa.py + SQLite cenova_mapa.db. Data pocházela z ULTIMATE_MASTER.db (98 198 reálných inzerátů) jako agregované statistiky (medián, průměr) per kombinace typ+město.

Statistiky

  • 17 202 vzorků z reálných prodejů
  • 2 136 kombinací (typ + město)
  • 1 713 měst
  • 9 typů: byt, dum, pozemek, garaz, komercni, chata, bd, ...

Výstup — HOT tagy

Tag Prahová hodnota Popis
HOT-40 40%+ pod trhem Extrémní příležitost
HOT-30 30–40% Výborná příležitost
HOT-20 20–30% Dobrá příležitost
HOT-10 10–20% Mírně pod trhem
NORM -20% až +10% Normální cena
PRICY 20%+ nad trhem Předraženo

API (port 5088)

python cenova_mapa.py --estimate BYT Praha 70 --price 5000000
POST /api/estimate  {"property_type": "BYT", "city": "Praha", "area": 70, "price_inzerat": 5000000}

Omezení

  • Bez GPS — čistě textové město
  • Mediány z inzerátů, ne reálných prodejů
  • Žádný ML model, jen agregace

3. Fáze 1a — overnight_price_scraper (2025-12)

Paralelně se statistickou mapou vznikl overnight scraper — Python skript spouštěný nočně (cron), který aktualizoval ceny z portálů. Nacházel nové inzeráty, spočítal denní mediány a přidal je do cenové DB.

Logika: každou noc projít portály → aktualizovat city_stats.db → refresh mediánů. Vznikla i verze v2 (overnight_scraper_v2) s lepším parsováním a dedulikací.


4. Fáze 1b — Cenová Kalkulačka 2025 (2026-01-14)

Co to bylo

První veřejná webová stránka na router.czechai.io. HTML/CSS/JS formulář: zadáš typ, město, plochu a dostaneš odhadovanou cenu. Backend volal statistickou mapu (5088).

Architektura

Browser → router.czechai.io/cenova-kalkulacka → Flask (5088) → city_stats.db

Klíčová Python logika

# cenova_kalkulacka_2025.py
def estimate_price(typ: str, mesto: str, plocha: float) -> dict:
    record = db.query("SELECT median_m2 FROM city_stats WHERE city=? AND property_type=?", mesto, typ)
    if not record:
        record = db.query("SELECT median_m2 FROM okres_stats WHERE okres LIKE ?", f"%{mesto}%")
    price_m2 = record['median_m2'] if record else NATIONAL_MEDIANS[typ]
    return {"estimated_price": price_m2 * plocha, "price_per_m2": price_m2}

Dokument CENOVA_KALKULACKA_2025_KOMPLETNI v Outline popisuje kompletní implementaci včetně Flask route /api/estimate, formuláře a deploymentu.


5. Fáze 2 — Čtyři základní mapy (2026-01 až 2026-02)

Tato fáze přinesla čtyři samostatné Flask/Python API servery, každý s jiným zdrojem dat a přístupem. Spolu tvořily "vrstvu 1" budoucího systému.


5.1 Mapa 1 — Prodeje V4 (port 5091)

Soubor: /opt/cenova_mapa/mapa1_prodeje/app.py (277 řádků) Databáze: city_stats.db (1.8–2.2 MB)

Datové struktury:

city_stats = {}   # dict: (city, ptype) -> {median_m2, mean_m2, count}
okres_stats = {}  # dict: (okres, ptype) -> {median_m2, mean_m2, count}

NATIONAL_MEDIANS = {
    "byt": 85000, "dum": 42000, "pozemek": 3100, "komercni": 35000
}

Cascade lookup: město (exact) → město (partial) → okres → národní fallback

Konfidence: 0.85 (city exact), 0.70 (partial), 0.60 (okres), 0.30 (national)

API:

POST/GET /api/estimate  {typ, mesto, plocha}
GET /api/cities         # vracíálla města
GET /api/stats
GET /api/health


5.2 Mapa 2 — CSU V4 (port 5092, STOPPED)

Soubor: /opt/cenova_mapa/mapa2_csu/app.py (196 řádků) Sdílí city_stats.db s Mapou 1 — ale přidává sezónní korekci a krajské fallbacky.

Sezónní koeficienty:

SEASONAL_COEFF = {1: 0.97, 2: 0.98, 3: 1.00, 4: 1.02, 5: 1.03, 6: 1.02,
                  7: 0.99, 8: 0.98, 9: 1.01, 10: 1.02, 11: 0.99, 12: 0.96}

Krajské mediány (14 krajů, kompletní tabulka): - Praha: byt 135 000, dům 90 000, pozemek 12 000 Kč/m² - Jihomoravský: byt 85 000, dům 42 000 - Moravskoslezský: byt 40 000, dům 25 000 - Středočeský: byt 65 000, dům 45 000 - Plzeňský: byt 62 000, dům 38 000 - … (14 krajů celkem)

5-stupňový cascade: city_exact → city_partial → okres → kraj → national


5.3 Mapa 3 — AI V7 / V8 (port 5093)

Soubor: /opt/cenova_mapa/mapa3_ai/app.py (358 řádků) Modely: /tmp/cenova_mapa_v7/ — trénováno na 225 000 záznamech

Modely a velikosti: | Soubor | Velikost | Typ | |--------|----------|-----| | model_xgb.pkl | 19 MB | XGBoost (primary) | | model_xgb_m2.pkl | 11 MB | XGBoost per-m² | | model_lgb.pkl | 3.3 MB | LightGBM | | model_gbr.pkl | 6.5 MB | GradientBoosting | | label_encoder_ptype.pkl | 286 B | Label encoder | | ensemble_weights.json | 115 B | Váhy ensemblu | | feature_cols.json | 248 B | Feature sloupce |

17 features:

[area, lat, lon,
 dist_prague,         # haversine(lat,lon, 50.08, 14.44)
 city_median_m2,      # z city_stats cache
 ptype_encoded,       # label_encoder.transform
 population,          # z city_pop dict
 elevation,           # z geodat
 is_praha, is_krajske_mesto,
 log(area), area^2,
 interactions...]

Přesnost (MdAPE): | Typ | MdAPE | |-----|-------| | BYT | 7.6% | | DUM | 15.3% | | KOMERCNI | 11.1% | | POZEMEK | 42.3% |

Caps konfidence: byt=0.85, dům=0.72, komerční=0.65, pozemek=0.40

API:

POST/GET /api/estimate  {typ, mesto, plocha, lat?, lon?}
GET /api/compare        → tag D10/D15/D20/D30/FAIR/P10/P20+


5.4 Mapa 4 — Smart Engine (port 5098)

Soubory: - /opt/cenova_mapa/mapa4_smart/app.py (687 řádků) - /opt/cenova_mapa/mapa4_smart/real_estate_engine.py (421 řádků) - /opt/cenova_mapa/mapa4_smart/price_map_classifier.py (298 řádků)

Taxonomie — 13 podtypů → 4 DB typy:

_SUBTYPE_TO_DB_PTYPE = {
    "APARTMENT": "byt",
    "HOUSE": "dum",
    "COTTAGE": "dum",            # korekce 0.65
    "LAND_BUILDING": "pozemek",
    "LAND_AGRICULTURAL": "pozemek",  # korekce 0.02
    "LAND_FOREST": "pozemek",        # korekce 0.01
    "LAND_GARDEN": "pozemek",        # korekce 0.15
    "LAND_FISH_POND": "pozemek",     # korekce 0.05
    "COMMERCIAL_OFFICE": "komercni",
    "COMMERCIAL_RETAIL": "komercni",
    "COMMERCIAL_WAREHOUSE": "komercni",
    "COMMERCIAL_PRODUCTION": "komercni",
    "GARAGE": "komercni",
}

Detekce junk inzerátů: - Pronájmy (pronájem), podíly (spoluvlastnictví), dražby, poptávky (koupím) → is_junk=True

Efektivní plocha:

total = area + terasa*0.5 + sklep*0.25 + balkon*0.5

MAD outlier detection:

outlier = |xi - median| > n_sigma * MAD * 1.4826

Sanity limity cen Kč/m²: - BYT: 10 000–350 000 - DUM: 5 000–200 000 - POZEMEK stavební: 100–50 000 - KOMERČNÍ: 5 000–250 000

API:

POST/GET /api/estimate   (klasifikace + korekce podtypu + MAD check)
POST /api/classify       {title, description} → {asset_class, subtype, confidence}
GET /api/taxonomy        (celá taxonomie s keywords)
GET /api/compare


5.5 Mapa 5 — Fusion Engine (port 5094)

Soubor: /opt/cenova_mapa/mapa5_fusion/app.py (867 řádků) 4 DB zdroje:

DB Záznamy Obsah
cuzk_cenove_udaje.db 30 872 Katastrální transakce Praha 2025
csu_ceny_nemovitosti.db 45 184 CSU celá ČR 2013–2024
master_live.db ~42 700 Multi-portálové nabídky
stat_realit_179k.db 179 000 Historické inzeráty

Klíčová inovace — korekce nabídka→realizace:

DEFAULT_CORRECTIONS = {
    "live":   {"BYT": 0.81, "DUM": 0.78, "POZEMEK": 0.86, "KOMERCNI": 0.76},
    "prodej": {"BYT": 0.86, "DUM": 0.83, "POZEMEK": 0.90, "KOMERCNI": 0.82},
}
(Byty se prodávají za ~81 % inzerované ceny)

Geografická adjustace korekce: - Praha: +0.03 - Brno: +0.02 - Krajská města: +0.01

Váhy zdrojů:

SOURCE_WEIGHTS = {
    "cuzk":   0.95,  # katastrální transakce = nejvyšší důvěryhodnost
    "csu":    0.85,  # oficiální statistika
    "prodej": 0.70,  # historické inzerátní ceny
    "live":   0.65,  # aktuální nabídky (nejméně spolehlivé)
}


6. Fáze 3 — Super Maps éra (2026-02 až 2026-03)

Super Maps byla vrstva orchestrátorů nad základními mapami. Cílem bylo kombinovat více enginů a eliminovat outliers.


6.1 Super Fetcher (library, bez HTTP)

Soubor: /opt/cenova_mapa/super_maps/super_fetcher.py (366 řádků) Zero HTTP závislosti — čte přímo z DB a pickle modelů.

8 interních enginů:

_est_prodeje()      → mediány z city_stats.db
_est_csu()          → CSU mediány + sezónní korekce
_est_ai()           → ML ensemble přímo z pickle modelů
_est_smart()        → klasifikace + korekce (zjednodušená)
_est_portaly()      → mediány z portaly_2026.db
_est_vynosovy()     → kapitalizace nájmu (CAP_RATE 4.5% pro byty)
_est_nakladovy()    → reprodukční cena × lokální koeficient (Praha: 2.32)
_est_valuo_trzni()  → vážený průměr prodeje + CSU

Výnosová metoda:

NAJMY_M2 = {"byt_velke": 430, "byt_stredni": 300, "byt_male": 240, "dum": 200}
CAP_RATES = {"byt": 0.045, "dum": 0.038, "komercni": 0.055}
price = (najem_m2 * plocha * 12) / cap_rate

Nákladová metoda:

REPRODUKCNI_M2 = {"byt": 65000, "dum": 50000, "komercni": 55000}
LOKALNI_KOEF = {"praha": 2.32, "brno": 1.85, "ostrava": 1.25, "plzen": 1.55}
price = reprodukcni_m2 * plocha * lokalni_koef * opotrebeni


6.2 Super Ensemble (port 7003) — Accuracy-Weighted

Soubor: /opt/cenova_mapa/super_maps/super_ensemble.py (149 řádků)

Váhy enginů = 1 / MAPE² (lepší engine = vyšší váha).

weight_i = 1 / (mape_i ** 2)
price = sum(price_i * weight_i) / sum(weight_i)
confidence = agreement * 0.6 + coverage * 0.4
# agreement = jak blízko jsou si odhady (1.0 = všechny stejné)
# coverage = počet respondujících enginů / celkem

6.3 Super Precision (port 7001) — Per-Type Optimal Weights

OPTIMAL_WEIGHTS = {
    "byt": {"ai": 0.30, "valuo_trzni": 0.18, "prodeje": 0.15,
            "smart": 0.12, "csu": 0.10, "vynosovy": 0.08, "nakladovy": 0.07},
    ...
}
2-sigma outlier removal před váženým průměrem.


6.4 Super Conservative (port 7002) — Safety Factor

  1. Seber odhady ze všech enginů
  2. Seřaď vzestupně
  3. Vyber 3 nejnižší
  4. Spočítej medián
  5. Vynásob safety_factor = 0.92

6.5 Super Unified (port 7000) — Všechny 3 strategie najednou

Soubor: /opt/cenova_mapa/super_maps/super_maps_unified.py (633 řádků) Sub-10ms response time (zero HTTP, přímý DB přístup).

80+ GPS měst, Praha po districtech:

PRAHA_DISTRICTS = {
    "Praha 1": {"byt": 170000, "dum": 130000, "pozemek": 45000},
    "Praha 2": {"byt": 145000, "dum": 110000, "pozemek": 35000},
    "Praha 3": {"byt": 120000, "dum":  90000, "pozemek": 22000},
    ...  # Praha 1–10
}

Size adjustment (byty):

< 30 m²: × 1.15    # garsonka premium
< 50 m²: × 1.05    # malý byt
> 100 m²: × 0.90   # velký byt diskont
> 150 m²: × 0.82   # mezonet

API:

GET /api/estimate  {
  "precision":    {"price": 5100000, "price_m2": 85000, "confidence": 0.82},
  "conservative": {"price": 4600000, "price_m2": 76667, "confidence": 0.75},
  "ensemble":     {"price": 5000000, "price_m2": 83333, "confidence": 0.80},
  "recommended": "precision"
}


6.6 Valuo Proxy Engines (porty 6000–6100)

5 služeb jako jednoduché HTTP proxies na Super Unified (7000):

Proxy Port Target
valuo-unified 6000 → 7000/api/precision
valuo1-trzni 6001 → 7000/api/precision (tržní sub-odhad)
valuo2-vynosovy 6002 → 7000/api/precision (výnosový sub-odhad)
valuo3-nakladovy 6003 → 7000/api/precision (nákladový sub-odhad)
valuo-pro 6100 → 7000/api/precision

6.7 Oceňovač — GPS/KNN (port 5300)

Soubor: /opt/ocenovac/app.py (237 řádků), FastAPI async Databáze: stat_realit.db (2026 live) + mega_training_data_v5.db (2025 historical)

K-nearest neighbors (k=15):

def haversine(lat1, lon1, lat2, lon2) -> float:
    # vzdálenost v km

async def gps_knn_estimate(typ, lat, lon, plocha, k=15) -> dict:
    # 1. Query oba DB zdroje
    # 2. Haversine ke každému záznamu
    # 3. Seřaď, vyber top-K
    # 4. Inverse distance weighting: weight_i = 1 / (dist_i + 0.001)
    # 5. 2026 data bonus: weight_i *= 1.20
    # 6. price_m2 = sum(price_i * weight_i) / sum(weight_i)

Strategie: GPS KNN 5km (min 5) → GPS KNN 15km (min 3) → city fallback


6.8 Market Intel (port 5400)

Soubor: /opt/market_intel/app.py (357 řádků), FastAPI async

Trendová analýza z živých dat (2026) vs historických (2025):

trend = (avg_price_m2_2026 - avg_price_m2_2025) / avg_price_m2_2025 * 100
investment_score = trend_component(40%) + liquidity_component(30%) + variance_component(30%)


6.9 Mapa Levon (port 6200)

Soubor: /opt/mapa_levon/app.py (478 řádků), FastAPI Data: JSON index — 17 000+ city+type kombinací

Dynamické diskonty:

DISCOUNTS = {"praha": 0.92, "krajske": 0.90, "other": 0.88}

4-stupňový cascade: city exact → okres → region → city partial


6.10 CSU Engine (port 5102)

Databáze: csu_ceny_nemovitosti.db - 45 184 cenových záznamů - 4 640 indexů - 100 542 výstavba záznamů (6 274 obcí)

30+ ručních aliasů (Praha→Praha, brno→Brno-mesto, atd.)


6.11 Smart Router (port 5150)

Soubor: /opt/cenova_mapa/smart_router/app.py (373 řádků)

3-vrstvový routing: 1. Layer 1 — DB Median (MAPE 35%): query city_stats.db 2. Layer 2 — Oceňovač KNN (MAPE 63%): HTTP → port 5300 3. Layer 3 — LLM Fallback: LiteLLM proxy (aurum-fast)

Podporuje rozšířené typy: BYT, DUM, POZEMEK, KOMERČNÍ, GARÁŽ, POLE, LES, LOUKA, ZAHRADA


6.12 Super-Ensemble V2 (port 5111)

Soubor: /opt/super-ensemble-v2/app.py (975 řádků), FastAPI async

Engine Registry — 7+1 enginů: | Engine | Port | Váha | Kategorie | Poznámka | |--------|------|------|-----------|----------| | prodeje | 5091 | 1.5 | tržní | Reálné tržní ceny z 105K+ | | ai_v8 | 5093 | 1.1 | ai_ml | Sníženo z 1.3 (MAPE 27% BYT) | | ocenovac | 5300 | 1.2 | knn | GPS/KNN | | mapa_levon | 6200 | 1.0 | statistical | 17K+ kombinací | | vynosovy | 6002 | 0.8 | výnosový | proxy → 7000 | | nakladovy | 6003 | 0.9 | nákladový | proxy → 7000 | | csu_katastr | 5102 | 1.3 | tržní | 45K katastrálních transakcí |

(smart 5098 odstraněn — zombie process)

Paralelní volání: asyncio.gather(*tasks), timeout 8s per engine

Agregace (V2.2 algoritmus): 1. De-duplikace (2 enginy se stejnou cenou → odeber 1) 2. Rozdělení: tržní vs výnosový vs nákladový 3. IQR outlier removal POUZE na tržní enginy 4. Final price = POUZE tržní enginy (vážený průměr) 5. Aplikace znaleckých vah (trojmetoda)

Znalecké váhy (trojmetoda):

ZNALECKE_VAHY = {
    "BYT":      {"trzni": 0.65, "nakladovy": 0.20, "vynosovy": 0.15},
    "DUM":      {"trzni": 0.60, "nakladovy": 0.25, "vynosovy": 0.15},
    "POZEMEK":  {"trzni": 0.80, "nakladovy": 0.10, "vynosovy": 0.10},
    "KOMERCNI": {"trzni": 0.40, "nakladovy": 0.25, "vynosovy": 0.35},
}

Korekce nemovitostí:

KOREKCE_STAV = {
    "novostavba": 1.10, "po_rekonstrukci": 1.08, "velmi_dobry": 1.03,
    "dobry": 1.00, "pred_rekonstrukci": 0.85, "spatny": 0.70
}
KOREKCE_PATRO = {0: 0.92, 1: 0.97, 2: 1.00, 3: 1.01, 4: 1.02, 5: 1.02, 6: 1.03}
KOREKCE_DISPOZICE = {
    "1+kk": 1.05, "1+1": 1.03, "2+kk": 1.02, "2+1": 1.00,
    "3+kk": 0.98, "3+1": 0.96, "4+kk": 0.93, "4+1": 0.92
}
SPECIALNI_KOREKCE = {
    "exekuce": 0.70, "drazba": 0.75, "insolvence": 0.72,
    "podil_1_2": 0.55, "podil_1_3": 0.40, "podil_1_4": 0.32,
    "vecne_bremeno": 0.85, "zastava": 0.90, "najem": 0.88
}

LLM review (auto-trigger při odchylce >30%, nízké shodě, nebo <3 enginy): - Model: qwen3:32b via Ollama na GPU 217.198.112.170:11434 - Český komentář: proč je cena taková, rizika, doporučení

MCP rozhraní:

POST /mcp/tools/list → {"tools": [{"name": "czechai_price_estimate", ...}]}
POST /mcp/tools/call → {typ, mesto, plocha} → výsledek


6.13 Znalecký Panel — 3 AI znalci (port 5112)

Soubor: /opt/znalecky-panel/app.py (926 řádků), FastAPI async

3 znalci + Chairman:

ZNALCI = {
    "znalec_A": {"model": "qwen3:32b", "role": "Konzervativní", "temperature": 0.3, "weight": 1.5},
    "znalec_B": {"model": "qwen3:32b", "role": "Optimistický",  "temperature": 0.7, "weight": 1.2},
    "znalec_C": {"model": "qwen3:32b", "role": "Pragmatický",   "temperature": 0.3, "weight": 1.0},
}
CHAIRMAN = {"model": "aurum-brain:latest", "role": "Předseda — finální verdikt"}

Data gathering (paralelně): 1. RAG (port 8095) — relevantní dokumenty 2. Sreality MCP (port 5055) — aktuální inzeráty 3. CNB MCP (port 5055) — úrokové sazby 4. Super-Ensemble v2.1 (5111) — strojový odhad 5. Market Intel (5400) — trendová analýza

Konsenzus: vážený průměr, shoda <15% = "vysoká", <30% = "střední"

Fast mode (?fast=true): deterministický bez LLM (~2s vs ~4 min)


6.14 Architektura v době dokumentace (2026-03-07)

Jak byl systém zdokumentován v MAPA_KOMPLETNI_DESKTOP:

28 služeb, 20 ONLINE, 8 STOPPED 9 273 řádků Python kódu + ~2 000 TypeScript (Next.js map)

Vrstvy systému:

VRSTVA 5 (Prezentace):    map-czechai (5800) — Next.js, 13K+ listingů, AI chat, PostgreSQL
VRSTVA 4 (Expert panel):  znalecky-panel (5112), super-ensemble-v2 (5111)
VRSTVA 3 (Agregace):      super-unified (7000), unified-price-api (5099), smart-router (5150)
VRSTVA 2 (Pokročilé):     mapa5-fusion (5094), mapa4-smart (5098), mapa3-ai (5093)
                          ocenovac (5300), mapa-levon (6200), csu-engine (5102)
VRSTVA 1 (Základní):      mapa1-prodeje (5091), mapa2-csu (5092), market-intel (5400)
VALUO PROXIES:            6001,6002,6003,6100,6000 → 7000

Datový tok:

Scraper (server 134) → MASTER_LIVE.db (42.7K) → city_stats.db (mediány)
         ML training: 225K záznamů → XGB+LGB+GBR V7 modely
   User request → Super-Ensemble v2 (5111) → 7 enginů paralelně
               → IQR outlier removal → znalecké váhy → korekce
               → optional: LLM review / Znalecký panel


7. Fáze 4 — Perfect Map V13 (2026-03-10, port 5131)

Motivace

Super-Ensemble v2 byl komplexní, ale závisel na HTTP volání 7 enginů. Cílem V13 bylo vytvořit jednu self-contained ML mapu s lepší přesností.

Architektura

PM2: perfect-map-v13 (ID 157) Cesta: /opt/cenova_mapa/perfect_map_v13/03_perfect_map_api.py

Data: - 296 291 čistých záznamů z 6 databází (čistění, deduplication, outlier removal) - 20 564 geo-lokalit - Hlavní DB: city_stats.db + CUZK + CSU + LIVE + stat_realit + portaly

ML model — HistGradientBoosting + Meta-learner:

Vrstva 1: HistGradientBoostingRegressor (sklearn)
         → 5-fold cross-validation → OOF předpovědi
Vrstva 2: Meta-learner (LinearRegression)
         → blenduje OOF výstupy

Výsledky: R² = 0.833, MAE = 15 687 Kč

5 geo-úrovní (cascade):

GPS4 → GPS3 → city+bucket → city → national

D-tagy: - D30 (30%+ pod trhem), D20, D15, D10, FAIR, P20+ (20%+ nad trhem)

API:

GET /api/estimate?typ=byt&mesto=Praha&plocha=60
GET /api/compare?typ=byt&cena=5500000&plocha=55&mesto=Praha
GET /api/taxonomy    # typy, D-tagy, velká města
GET /api/cities      # top města s mediány
GET /api/stats
GET /api/health


8. Fáze 5 — V15 (2026-04, port 5150)

V15 nahradil Smart Router na portu 5150. Šlo o dedikovaný ML model s lepší architekturou než V7, ale ještě bez dispozice jako feature.

PM2: cenova-mapa-v15-shadow-combo3 (port 5165 v produkci na serveru 94)

V15 se stal záložní (fallback) vrstvou pro typy pozemek a komerční v Combo3 routeru.


9. Fáze 6 — V24 (2026-04-24, port 5164)

Největší skok v přesnosti

Tréninkový skript: /opt/cenova_mapa/retrain_v24.py Experiment dir: /opt/cenova_mapa/experiments/combo3_2026-04-24/

Nové features — klíčová změna: dispozice

V24 přidal dispozice (1+kk, 2+1, 3+kk, …) jako feature, která předchozím modelům chyběla.

34 features pro BYT:

features_byt = [
    'plocha', 'lat', 'lon',
    'dispozice_num',            # ← NOVÉ: normalizovaná dispozice na číslo
    'dist_prague',
    'city_median_m2', 'city_count',
    'okres_median_m2', 'kraj_median_m2',
    'ptype_encoded',
    'log_plocha', 'plocha_sq',
    'is_praha', 'is_brno', 'is_ostrava',
    'is_krajske_mesto',
    'population', 'elevation',
    ...                         # celkem 34
]

Ensemble — 4 modely:

models = {
    "lgb":  LGBMRegressor(learning_rate=0.05, num_leaves=127, n_estimators=800),
    "xgb":  XGBRegressor(learning_rate=0.05, max_depth=6, n_estimators=800),
    "rf":   RandomForestRegressor(n_estimators=200, max_features=0.6),
    "knn":  KNeighborsRegressor(n_neighbors=15, weights='distance'),
}
# 5-fold OOF → stacking meta-learner

Váhy ensemblu:

{
  "BYT": {"lgb": 0.3363, "xgb": 0.3359, "rf": 0.3278},
  "DUM": {"lgb": 0.3373, "xgb": 0.3356, "rf": 0.3271}
}

Výsledky — dramatické zlepšení: | Typ | V13 R² | V24 R² | V24 median APE | |-----|--------|--------|----------------| | BYT | 0.833 | 0.9478 | 7.13% | | DUM | — | 0.9178 | — |

Log-target pro DUM: DUM model trénuje na log(price) → lepší chování pro velký rozptyl cen domů.


10. Fáze 6 — Combo3 Router (port 5163)

Soubor: /opt/cenova_mapa/combo3_router_5163.py PM2: cenova-mapa-combo3-shadow (ID 171)

Logika routování

def route_request(typ):
    if typ in ['byt', 'dum']:
        return forward_to_v24(5164)    # V24 primary
    else:
        return forward_to_v15(5165)    # V15 fallback pro pozemek/komerční

Normalizace parametrů

def normalize_params(params):
    # Typ aliasy: type→typ, area→plocha, city→mesto
    # Město aliasy: type→typ atd.
    # Dispozice: "2+1" → číslo 2.5

Timeout: 8s, fallback transparent k clientovi.


11. Fáze 7 — shadow.czechai.io — Produkce (2026-05-03)

Infrastruktura

DNS shadow.czechai.io → 46.224.121.179 (server 179, SSL terminator)
Nginx 179: proxy_pass → http://94.130.223.40
Nginx 94: HTTP+HTTPS → PM2 procesy (5163/5166)

PM2 na serveru 94 (94.130.223.40): | PM2 name | Port | Popis | |----------|------|-------| | cenova-mapa-combo3-shadow | 5163 | Combo3 router (PRIMARY endpoint) | | cenova-mapa-v24-shadow-combo3 | 5164 | V24 model (přímý) | | cenova-mapa-v15-shadow-combo3 | 5165 | V15 model (fallback) | | shadow-url-estimator | 5166 | Bridge: URL/adresa → odhad/council/adjudicate |

Hlavní service: /opt/czechai/shadow_url_estimator.py


Veřejné API endpointy (shadow.czechai.io)

Endpoint Metoda Popis
/v1/cenova/estimate GET/POST Univerzální odhad z adresy nebo URL inzerátu
/v1/cenova/from-address GET Odhad z adresy
/v1/cenova/from-url GET Odhad z URL inzerátu
/v1/cenova/adjudicate GET/POST Arbiter → APPROVE/CONFIRM/REVIEW/NEGATE
/v1/cenova/council GET/POST Valuation Council (produkce + CMA)
/v1/cenova/admin/stats GET Admin statistiky (token)
/v1/cenova/admin/events GET Admin eventy (token)

Veřejné stránky: - /cenovy-odhad — veřejný formulář - /widget/cenova-widget.js — embeddable widget - /cenova-admin — admin panel - /cenova-api — API dokumentace - /v1/cenova/openapi.json — OpenAPI spec - /health — health check


Výstup odhadu (co API vrací)

{
  "cena": 5200000,
  "cena_m2": 86667,
  "interval": {"low": 4800000, "high": 5600000},
  "confidence": 0.87,
  "explanation": "Na základě 234 srovnatelných nemovitostí...",
  "comparable_properties": [...],
  "spatial_neighbor_correction": 1.02,
  "hedonic_avm_layer": {...},
  "investment_metrics": {...},
  "arbitration_verdict": "CONFIRM"
}

EstateX Direct CMA Agent

Soubor: /opt/czechai/estatex_cma_agent.py MCP: mcp/estatex-cma-mcp/server.mjs DB: /opt/reality-pipeline/data/MASTER_LIVE.db

Nezávislý agent bez V24 — vážený medián podle vzdálenosti/podobnosti/zdroje. - Deduplikuje cílovou nemovitost podle URL/GPS/plochy/ceny - Městský filtr: zamezuje míchání GPS z jiných měst do Prahy

Benchmark (100 vzorků): | Agent | Median APE | Byty APE | |-------|-----------|---------| | Direct CMA | 24.68% | 14.23% | | V24 | 7.13% | 10.83% |

→ V24 je primární model; Direct CMA = nezávislá kontrolní vrstva


EstateX Valuation Council

CLI: scripts/estatex_valuation_council.mjs MCP: mcp/estatex-council-mcp/server.mjs Produkční endpoint: /v1/cenova/council

Logika verdiktu:

produkce NEGATE  → NEGATE (bez diskuse)
produkce REVIEW  → REVIEW
CMA vs produkce ≥ 25% → REVIEW
CMA vs produkce ≥ 15% → CONFIRM (s výhradou)
nízká confidence       → CONFIRM
rozdíl < 15% + dobrá CMA confidence → blend 78% produkce + 22% CMA → APPROVE


EstateX Opportunity Brain

Soubor: scripts/estatex_opportunity_brain.py Model: /opt/czechai/estatex_opportunity_brain.joblib (ExtraTrees) Výsledky tréninku: 93 885 řádků, MAE ~16 758 Kč/m², MAPE ~47.82%, R² log ~0.8186, 3 331 segmentů

Výstup: fairMarketPriceCzk, maxReasonableBuyPriceCzk, targetOfferCzk


12. Kompletní portová mapa (všechny verze)

Port Služba Fáze Stav
5088 Stat. mapa (portaly 2026 fallback) 1a archív
5091 Mapa 1 — Prodeje V4 2 deprecated
5092 Mapa 2 — CSU V4 2 deprecated
5093 Mapa 3 — AI V7/V8 2 deprecated
5094 Mapa 5 — Fusion Engine 2 deprecated
5097 Mapa 5 — Timeseries 2 stopped
5098 Mapa 4 — Smart Engine 2 deprecated
5099 Unified Price API (Levon+AI+Smart) 3 stopped
5100 Cenova Ultimate (simple median) 3 stopped
5102 CSU Engine 3 stopped
5111 Super-Ensemble V2 (7 enginů) 3 stopped
5112 Znalecký Panel (3 AI znalci) 3 stopped
5131 Perfect Map V13 4 deprecated
5150 Smart Router / V15 model 3/5 záloha
5163 Combo3 Router (PRODUKCE) 6 ✅ LIVE
5164 V24 direct 6 ✅ LIVE
5165 V15 direct (fallback) 5/6 ✅ LIVE
5166 Bridge (URL/adresa → estimate) 7 ✅ LIVE
5300 Oceňovač GPS/KNN 3 stopped
5400 Market Intel 3 stopped
5800 Map-CzechAI (Next.js) 3 stopped
6000–6003 Valuo proxies → 7000 3 stopped
6100 Valuo-pro → 7000 3 stopped
6200 Mapa Levon (17K kombinací) 3 stopped
7000 Super Unified (3 strategie) 3 stopped
7001 Super Precision 3 stopped
7002 Super Conservative 3 stopped
7003 Super Ensemble (MAPE-weighted) 3 stopped

13. Datové zdroje (přehled všech DB)

Soubor Záznamy Obsah Používá
ULTIMATE_MASTER.db 98 198 Nejstarší master DB archív
city_stats.db 105K+ listings Mediány per město+typ Mapa 1, 2, Super Fetcher
cuzk_cenove_udaje.db 30 872 Katastr Praha 2025 Fusion, CSU engine
csu_ceny_nemovitosti.db 45 184 CSU celá ČR 2013–2024 Fusion, CSU engine
stat_realit_179k.db 179 000 Historické inzeráty Fusion, Oceňovač
MASTER_LIVE.db 42 700–246 000 Multi-portálové live Fusion, CMA agent
mega_training_data_v5.db historická Training data 2025 Oceňovač
cenova_estimates.sqlite3 live log Produkční odhady shadow.czechai.io
map_czechai (PostgreSQL) 13 456 Listings pro mapu Map-CzechAI

14. ML modely — evoluce přesnosti

Model Trénováno Záznamy Metrika BYT
AI V7 (XGB+LGB+GBR) ~2026-01 225 000 MdAPE 7.6%
AI V8 ~2026-02 ~27%*
Perfect Map V13 2026-03-10 296 291 0.833
V24 (LGB+XGB+RF+KNN) 2026-04-24 0.9478

*V8 regresoval na MAPE 27% pro BYT — proto byla jeho váha v Super-Ensemble snížena z 1.3 na 1.1


15. Pravidla pro produkci (platí vždy)

🔴 ABSOLUTNÍ PRAVIDLA:

1. Port 5163 (Combo3) = JEDINÝ správný port pro cenovou mapu
   ZAKÁZÁNO: 5131 (V13), 5150 (V15), 5154 (starý V24), 5111 (Super-Ensemble)

2. API volání V24:
   - plocha → posílat jako area i plocha
   - typ   → posílat jako type i typ
   - město → posílat jako city i mesto
   - dispozice (2+kk / 3+1) → normalizovat na číslo

3. Sreality URL nikdy neupravovat — přesně jak jsou v DB

4. AML systém nesahat bez explicitního souhlasu

16. Klíčové soubory v repository

scripts/shadow_url_estimator.py          # Bridge: URL/adresa → odhad
scripts/estatex_cma_agent.py             # Direct CMA (bez V24)
scripts/estatex_valuation_agent.mjs      # CLI agent
scripts/estatex_valuation_council.mjs    # Council CLI
scripts/estatex_opportunity_brain.py     # Opportunity Brain (ExtraTrees)
scripts/evaluate_cma_vs_v24.py           # Benchmark script
scripts/cenova_e2e_test.mjs              # E2E testy
mcp/estatex-valuation-mcp/server.mjs     # MCP pro valuation
mcp/estatex-opportunity-mcp/server.mjs  # MCP pro opportunity
mcp/estatex-cma-mcp/server.mjs          # MCP pro CMA
mcp/estatex-council-mcp/server.mjs      # MCP pro council
tmp/nginx/shadow.czechai.io              # Nginx config template
server.mjs / package.json               # Main server
docs/ESTATEX_DIRECT_CMA_AGENT.md
docs/ESTATEX_VALUATION_COUNCIL.md
docs/CMA_VS_V24_BENCHMARK_100.md


17. Benchmark — všechny mapy najednou (2026-03-02)

Testovací nemovitost: BYT Praha 75 m² | Server: 46.224.121.179

Výsledky (seřazeno dle pořadí v architektuře)

# Mapa Port Odhad (CZK) CZK/m² Confidence Čas
1 Super-Ensemble v2.1 5111 10 228 890 136 385 0.95 0.2s
2 Znalecký Panel (3 AI) 5112 10 595 059 141 267 0.79 53s
3 Prodeje V4 5091 12 417 339 165 565 0.90 <50ms
4 AI V8 (4 ML) 5093 11 117 448 148 233 1.00 <50ms
5 Oceňovač GPS/KNN 5300 12 376 206 165 016 0.90 880ms
6 Mapa Levon 6200 10 790 539 143 874 0.88 <100ms
7 Market Intel 5400 (kontext) med 184k <200ms
8 Valuo Pro (3-way) 6100 11 951 689 159 355 0.70 <100ms
9 Valuo Výnosový 6002 4 760 000 63 466 0.70 <50ms
10 Valuo Nákladový 6003 9 450 000 126 000 0.70 <50ms

Rozpětí tržních enginů (bez výnosového/nákladového): - Min: 10 228 890 CZK (SE v2.1) - Max: 12 417 339 CZK (Prodeje V4) - Spread: 21 % — akceptovatelné pro BYT v Praze

Detail klíčových enginů

Super-Ensemble v2.1 (5111):

Cena:          10 228 890 CZK (136 385 CZK/m²)
Shoda enginů:  0.928
Confidence:    0.95
Enginy:        6/6 OK
Tržní:         11 730 600 CZK
Výnosový:      4 760 000 CZK
Nákladový:     9 450 000 CZK
Review needed: false

Znalecký Panel (5112) — 3 AI znalci:

Znalec A (konzervativní, váha 1.5):  8 500 000 CZK  (conf 0.70)
Znalec B (optimistický, váha 1.2):  13 000 000 CZK  (conf 0.88)
Znalec C (pragmatický, váha 1.0):   10 228 890 CZK  (conf 0.93)
────────────────────────────────────────────────────────────
Konsenzus:                          10 595 059 CZK  (141 267/m²)
Shoda znalců:                       0.785
Data sources:                       4/5 OK (RAG, Sreality, ČNB, SE)
Čas:                                53.2s

Market Intel (5400) — Praha centrum, 3km radius:

Záznamy:        4 133 (1 031 live + 3 102 historické)
Trend:          stabilní (+3.3%)
Likvidita:      vysoká
Investment score: 82/100
Medián m²:      184 286 CZK
P25–P75:        158 469 – 216 687 CZK/m²

Přesnost podle typu nemovitosti (SE v2.1)

Typ Shoda enginů Confidence Review needed
BYT 0.928 0.95 NE
DUM 0.920 0.94 NE
POZEMEK 0.634 0.74 ANO
KOMERCNI 0.536 0.68 ANO

AI V8 benchmark přesnost (MdAPE)

Typ MdAPE
BYT 7.78%
DUM 18.19%
KOMERCNI 18.96%
POZEMEK 41.11%

Review mechanismus (automatický)

Dotaz → SE v2.1 (0.2s)
  ├── Shoda enginů > 0.70?
  │     └── ANO → výsledek (review_needed: false)
  └── NE (odchylka >30% mezi tržními enginy)
        ├── review_needed: true
        └── auto_review=true?
              ├── NE → jen flag, caller rozhodne
              └── ANO → Znalecký Panel (+53s)
                         ├── <15% → "SE a Panel se shodují"
                         ├── 15–25% → "Mírná neshoda – ruční kontrola"
                         └── >25% → "Velká neshoda – expertní revize"

Vrstvy architektury (2026-03-02, schéma)

DATABÁZE:
  city_stats.db (8 357 kombinací)
  stat_realit.db (39K live 2026)
  mega_training_data_v5.db (103K historické 2025)
  mapa_levon_index.json (17K+ kombinací)
  ML modely (XGB, LGB, GB, CatBoost)
LAYER 1 (jednotlivé enginy):
  5091 Prodeje V4     |  5093 AI V8 (4 ML)
  5300 Oceňovač KNN   |  6200 Mapa Levon
  6002 Výnosový       |  6003 Nákladový
LAYER 2 (agregátory):
  5111 SUPER-ENSEMBLE v2.1
       6 enginů + IQR + vážený medián + 3 přístupy
       + Market Intel + LLM + AUTO REVIEW → 5112

  5112 ZNALECKÝ PANEL v1.0
       3 AI znalci (qwen3:32b) + RAG + MCP + ČNB
       + Chairman konsenzus (~53s)

  5400 MARKET INTEL
       Trendy, likvidita, investiční skóre, P25–P75

Klíčové DB (stav 2026-03-02)

Databáze Záznamy Použití
city_stats.db 8 357 kombinací Prodeje V4, AI V8
stat_realit.db 39K live 2026 Oceňovač, Market Intel, Valuo
mega_training_data_v5.db 103K hist. 2025 Oceňovač, Market Intel
mapa_levon_index.json 17K+ kombinací Mapa Levon
ML modely (.pkl) 4 modely × typ AI V8

Dokument generován 2026-05-04 · Claude Code (claude-sonnet-4-6) Zdroje: SSH server 179, PM2, /opt/outline/outline_backup_20260328.sql, MAPA_KOMPLETNI_DESKTOP (2026-03-07), SERVICE_MAP benchmark (2026-03-02)


18. Vědecká sekce — ETL GIS Pipeline (2026-04-15)

Tato sekce zachycuje kompletní ETL pipeline, která předcházela tréninku V23 a V24. Pipeline transformovala 138 056 surových zákazníků z databáze na GIS-obohacená tréninková data se 12 novými prostorovými features.

18.1 Proč GIS enrichment?

Předchozí modely (V7, V8, V13) používaly jako prostorové features pouze: - GPS souřadnice (gps_lat, gps_lon) — přímé - Vzdálenosti k velkým městům (d_praha, d_brno, ...) — vypočítané haversine - Mediány per město (city_median_m2) — z city_stats.db

Výzkum ukázal, že tyto features nestačí pro přesné ocenění v různých lokalitách. Nemovitost 500 metrů od dálnice vs 10 km se liší o 5–15 % v ceně — a model to neviděl. Proto vznikla GIS ETL pipeline.

18.2 Pipeline — 8 kroků

01_enrich_transport.py   → vzdálenost k silnicím, dálnici, MHD, počet zastávek
02_enrich_water.py       → vzdálenost k vodě/řece, zaplavovací zóna
03_enrich_landuse.py     → landuse typ, zelené plochy, POI score, vzdálenost ke škole
04_enrich_ruian.py       → PSČ medián (poštovní kódy → ceny)
05_merge_features.py     → merge všech 4 parquet souborů → enriched_v23.parquet
06_test_1000.py          → validační skript (1000 náhodných bodů)
07_train_v23_enriched.py → trénink V23 na obohacených datech
08_deploy_v23.sh         → deploy (V23 nikdy nasazen — viz sekce 22)
etl_06_add_dispozice.py  → klíčové: přidání dispozice → enriched_v24.parquet

18.3 ETL 01 — Transport features (2026-04-15 12:44)

Skript: /opt/cenova_mapa/etl/01_enrich_transport.py Čas běhu: 25 sekund Výstup: transport_features.parquet (138 056 řádků)

Vypočítané features:

distance_to_motorway      — vzdálenost k nejbližší dálnici (km)
distance_to_primary_road  — vzdálenost k hlavní silnici (km)
distance_to_mhd           — vzdálenost k nejbližší zastávce MHD (km)
mhd_stops_500m            — počet MHD zastávek v okruhu 500 m

Logy — sanity checks (PASSED ✅):

2026-04-15 12:44:28 === SANITY CHECKS ===
distance_to_motorway: min=0.00, max=68.77, mean=10.74 km
distance_to_mhd:      min=0.00, max=12.46, mean=0.40 km
mhd_stops_500m:       min=0, max=55, mean=4.7
Praha centrum (5936 bodů): MHD=0.163km, zastávky=13.7
Sanity checks PASSED ✅
Uloženo: /opt/cenova_mapa/etl/output/transport_features.parquet (138056 řádků)
Hotovo za 25s

Interpretace dat: - Průměrná vzdálenost k dálnici 10.74 km odpovídá hustotě silniční sítě ČR - Praha centrum: MHD zastávka průměrně 163 metrů, 13.7 zastávek v dosahu = hustá MHD síť - Max 55 zastávek v 500m = Florenc/hlavní uzly - Max vzdálenost MHD 12.46 km = vzdálené vesnice bez MHD

Technická implementace:

# Haversine kdtree pro rychlé hledání nejbližší zastávky
from scipy.spatial import cKDTree
import numpy as np

# GeoJSON datové sady (OpenStreetMap):
# - motorways: dálnice D1, D2, D3...
# - primary roads: silnice 1. třídy
# - MHD zastávky: Praha, Brno, Ostrava, regionální

tree_mhd = cKDTree(mhd_coords_radians)  # KD-Tree na sférických souřadnicích
dists, _ = tree_mhd.query(coords_radians, k=51)  # 51 = 1 cílový + 50 sousedů
distance_to_mhd = dists[:, 0] * 6371  # km
mhd_stops_500m = np.sum(dists[:, 1:] * 6371 < 0.5, axis=1)

18.4 ETL 02 — Water features (2026-04-15 12:45)

Skript: /opt/cenova_mapa/etl/02_enrich_water.py Čas běhu: 32 sekund Výstup: water_features.parquet (138 056 řádků)

Vypočítané features:

distance_to_water   — vzdálenost k nejbližší vodní ploše (rybník, jezero, nádrž) (km)
distance_to_river   — vzdálenost k nejbližší řece (km)
in_flood_zone       — boolean: leží v zaplavovací zóně Q100?

Logy — sanity checks (PASSED ✅):

2026-04-15 12:45:07 === SANITY CHECKS ===
distance_to_water:  min=0.000, max=8.65, mean=0.25 km
distance_to_river:  min=0.001, max=26.17, mean=2.75 km
in_flood_zone:      11189 bodů v záplavové zóně (8.1%)
Sanity checks PASSED ✅
Uloženo: /opt/cenova_mapa/etl/output/water_features.parquet (138056 řádků)
Hotovo za 32s

Interpretace dat: - 8.1 % nemovitostí v záplavové zóně — odpovídá reálnému podílu v říčních nivách - Průměrná vzdálenost k vodě 250 metrů = ČR je vodnatá země - Max vzdálenost k řece 26.17 km = suchá plateau

Datový zdroj: - Záplavové zóny: ČHMÚ data (Q100 = povodeň 1× za 100 let) - Vodní plochy a řeky: OpenStreetMap waterway + natural=water

Vliv na cenu nemovitosti: - Blízkost k vodě (< 300 m) → prémium +3–8 % - In_flood_zone=1 → diskont -5–12 % (pojistné riziko, hypotéky)

18.5 ETL 03 — Landuse features (2026-04-15 12:46–12:48)

Skript: /opt/cenova_mapa/etl/03_enrich_landuse.py Čas běhu: 172 sekund (nejdelší ETL krok) Výstup: landuse_features.parquet (138 056 řádků)

Vypočítané features:

landuse_type    — typ využití území (0-7, kódováno)
green_area_500m — podíl zelených ploch v okruhu 500 m (0.0–1.0)
poi_score_500m  — skóre dostupnosti bodů zájmu (0–100)
school_distance — vzdálenost k nejbližší škole (km)

Kódování landuse_type:

0 = residential (obytná zóna)  — 103 848 bodů (75.2%)
1 = mixed (smíšené využití)    — implicit fallback
2 = commercial (komerční)      — 348 bodů
3 = industrial (průmyslové)    — 1 323 bodů
4 = agricultural (zemědělské)  — 126 bodů
5 = park/green (park/zeleň)    — 5 983 bodů (4.3%)
6 = forest (les)               — 4 417 bodů (3.2%)
7 = water (voda)               — 53 bodů

Logy — sanity checks (PASSED ✅):

2026-04-15 12:48:00 === SANITY CHECKS ===
landuse_type dist: {1: 103848, 0: 21958, 5: 5983, 6: 4417, 3: 1323, 2: 348, 4: 126, 7: 53}
green_area_500m: mean=0.224, max=1.000
poi_score_500m:  mean=8.6, max=100.0
school_distance: mean=3.38km
Sanity checks PASSED ✅
Hotovo za 172s

POI score metodika:

POI_WEIGHTS = {
    "restaurant":       3,
    "cafe":             2,
    "supermarket":      5,
    "pharmacy":         4,
    "doctor":           3,
    "bank":             2,
    "public_transport": 6,
    "park":             2,
    "cinema":           1,
    "gym":              1,
}
# score = min(100, sum(count_i * weight_i) pro POI v okruhu 500m)

Interpretace: - green_area_500m mean=0.224 → průměrně 22.4 % zeleně v dosahu 500 m - poi_score max=100 = centrum Prahy/Brna (přes 100 bodů, cappováno) - school_distance mean=3.38 km → průměrně 3+ km ke škole (include rural areas)

18.6 ETL 04 — RUIAN / PSČ features (2026-04-15 12:48)

Skript: /opt/cenova_mapa/etl/04_enrich_ruian.py Čas běhu: 1 sekunda (fallback mode) Výstup: ruian_features.parquet (138 056 řádků)

Cíl: Přidat psc_median — medián ceny Kč/m² pro poštovní kód (PSČ)

Fallback mode — co se stalo:

2026-04-15 12:48:01 Training data: 138056 GPS bodů
2026-04-15 12:48:01 FALLBACK MODE: RUIAN CSV není dostupné, použiji PSČ z city_stats
2026-04-15 12:48:02   Unikátních PSČ nalezeno: 1
2026-04-15 12:48:02 PSČ mediánů: 1, global median: 47875 Kč/m²
2026-04-15 12:48:02 psc_median: min=47875, max=47875, mean=47875 Kč/m²
2026-04-15 12:48:02 psc_code sample: ['00000', '00000', '00000', '00000', '00000']

Problém: RUIAN CSV (Registr územní identifikace, adres a nemovitostí) nebyl v době ETL dostupný na serveru. Skript přešel do fallback módu a přiřadil všem nemovitostem globální medián 47 875 Kč/m².

Důsledek: Feature psc_median v V23/V24 modelu má nulovou informační hodnotu (konstantní). V budoucí verzi modelu by měla být nahrazena skutečnými PSČ mediány z RUIAN.

18.7 ETL 05 — Merge features (2026-04-15 12:48)

Skript: /opt/cenova_mapa/etl/05_merge_features.py Čas běhu: 7 sekund Výstup: enriched_v23.parquet (140 396 řádků, 35 sloupců)

Merge na klíčovém sloupci id — spojení všech 4 parquet souborů.

Logy — výsledky merge:

2026-04-15 12:48:02 Načítám base training data...
2026-04-15 12:48:03 Base training: 138056 záznamů
2026-04-15 12:48:03 Načítám enriched features...
2026-04-15 12:48:03   transport: 138056, water: 138056, landuse: 138056, ruian: 138056
2026-04-15 12:48:03 Merguju na id...
2026-04-15 12:48:03 Merged: 140396 záznamů
2026-04-15 12:48:05 Počítám V15 vzdálenostní features...
2026-04-15 12:48:09 Počítám mic/mac features...

=== SANITY CHECKS ===
Rozměr: (140396, 35)
Null hodnoty: Series([], dtype: int64)   ← žádné null hodnoty!

property_type distribuce:
  dum         54802   (39.0 %)
  byt         47063   (33.5 %)
  pozemek     32291   (23.0 %)
  komercni     6240    (4.4 %)

price_m2: min=6, max=8500000, mean=62666

V23 nové features stats:
  distance_to_motorway: min=0.00, max=68.77, mean=10.748
  distance_to_mhd: min=0.00, max=12.46, mean=0.399
  in_flood_zone: min=0.00, max=1.00, mean=0.081
  landuse_type: min=0.00, max=7.00, mean=1.205
  poi_score_500m: min=0.00, max=100.00, mean=8.570

Hotovo za 7s

Poznámka: Výsledek 140 396 řádků (vs 138 056 vstupu) — 2 340 nových záznamů přibylo při merge. Důvod: base data obsahovala záznamy s jinými ID než ETL výstupy, Pandas left join přidal NaN řádky, které pak byly doplněny mediány.

35 sloupců v enriched_v23.parquet:

id, property_type, city, area, price, price_m2, gps_lat, gps_lon,
log_area, d_praha, d_brno, d_ostrava, d_plzen, d_liberec, d_olomouc,
d_cb, d_hk, d_usti, d_pardubice, d_zlin, d_kv, d_jihlava,
d_min, mic_key, mac_key,
distance_to_motorway, distance_to_primary_road, distance_to_mhd,
mhd_stops_500m, distance_to_water, distance_to_river, in_flood_zone,
landuse_type, green_area_500m, poi_score_500m, school_distance, psc_median


19. ETL 06 — Klíčová inovace: dispozice feature (2026-04-24)

19.1 Co je dispozice a proč je to průlom

dispozice je typ bytu z pohledu počtu místností: 1+kk, 2+1, 3+kk, 4+1, 5+kk atd. Pro českou realitní trh je to fundamentální proměnná — cena za m² 2+kk bytu je výrazně jiná než stejně velký 1+kk nebo 3+1.

Příklad — Praha 60 m²: | Dispozice | Typická cena Kč/m² | Poznámka | |-----------|-------------------|----------| | 1+kk (jednobytový) | 120 000–140 000 | Garsonka premium | | 2+kk | 105 000–120 000 | Standardní | | 2+1 | 98 000–112 000 | Starší panelák | | 3+kk | 92 000–108 000 | Větší byt diskont | | 3+1 | 88 000–105 000 | Starší standard | | 4+kk | 82 000–98 000 | Velký byt |

Bez dispozice musel model hádat z pouhé plochy — a při 60 m² neví, jestli jde o prostorný 1+kk nebo stísněný 2+1. Chyba ±10 %.

19.2 Skript etl_06_add_dispozice.py

Soubor: /opt/cenova_mapa/etl_06_add_dispozice.py Datum spuštění: 2026-04-24 (před tréninkem V24)

#!/usr/bin/env python3
"""ETL 06 — Přidá dispozice (rooms) do enriched_v23.parquet → enriched_v24.parquet

Zdroj: mega_training_data_v6.db → dispozice (int: 1-6, 0=unknown)
BYT:  95.8% fill → median = 2
DUM/pozemek/komercni: dispozice = 0 (neaplikovatelné)

Výstup: /opt/cenova_mapa/etl/output/enriched_v24.parquet
"""
IN_FILE  = '/opt/cenova_mapa/etl/output/enriched_v23.parquet'
OUT_FILE = '/opt/cenova_mapa/etl/output/enriched_v24.parquet'
DB_PATH  = '/opt/cenova_mapa/MASTER_MAP_DB/training_data/mega_training_data_v6.db'

df = pd.read_parquet(IN_FILE)          # 140396 × 35
disp = pd.read_sql('SELECT id, dispozice FROM training_data', conn)
disp = disp.drop_duplicates('id')      # safety

df = df.merge(disp[['id', 'dispozice']], on='id', how='left')
df['dispozice'] = pd.to_numeric(df['dispozice'], errors='coerce').fillna(0).astype(np.int8)
df['dispozice'] = df['dispozice'].clip(0, 6)  # max 6+kk

# Sanity checks
assert df.isnull().sum().sum() == 0
assert df.shape[1] == 36       # 35+1 nová feature
assert len(df) == 140396       # počet řádků se nezměnil

df.to_parquet(OUT_FILE, index=False)
# Výstup: enriched_v24.parquet (140396 rows, 36 cols)

19.3 Fill rate dispozice per property_type

BYT:      95.8 % (44 946 / 46 916 bytů má dispozici)
DUM:       0.0 % (dispozice = 0, neaplikovatelné)
POZEMEK:   0.0 % (dispozice = 0, neaplikovatelné)
KOMERCNI:  0.0 % (dispozice = 0, neaplikovatelné)

Distribuce BYT dispozice:

0 (unknown):  2 117  (4.2 %)   → imputováno mediánem 2
1 (1+kk/1+1): 8 403 (16.7 %)
2 (2+kk/2+1): 19 862 (39.5 %)   ← nejčastější
3 (3+kk/3+1): 12 044 (23.9 %)
4 (4+kk/4+1):  5 391 (10.7 %)
5 (5+kk/5+1):  2 184  (4.3 %)
6 (6+ pokojů):    835  (1.7 %)

Mediánová imputace: Pro BYT s dispozice=0 (4.2 %) se při inferenci použije medián = 2 (2+kk/2+1).

Proč integer a ne string? Aby model mohl zachytit monotónní vztah: 1 < 2 < 3 < 4 < 5 < 6. Řetězce "2+kk" a "2+1" jsou sloučeny — rozlišení kk vs. +1 zůstává schováno ve ploše (2+1 typicky větší).


20. V15 iterace — kompletní vědecká evoluce (7 verzí)

V15 nebyla jedna verze — byl to výzkumný projekt s 7 iteracemi (b–h), kde každá experimentovala s jinou architekturou. Každá verze zůstala na serveru jako .py skript.

20.1 Kontext — proč iterovat od V15b?

V15a (nenazvaná) byla přímý nástupce Smart Routeru na portu 5150. Zbývá neznámá — v adresáři existuje jen train_v15_perfect.py bez b/c/d prefixu. Iterace b–h jsou systematické experimenty.

20.2 V15b — Direct price_m2 + micro-region KNN

Soubor: /opt/cenova_mapa/train_v15b.py Klíčová změna: Přímá predikce price_m2 (ne celkové ceny), micro-region KNN jako feature

Architektura:

Datový zdroj: mega_training_data_v6.db
Outlier removal: log-normální 2.5σ + micro-region relative (cena/median_micro < 0.3 nebo > 3.0)
Micro-region: (lat*100).round() + "_" + (lon*100).round() = ~1km čtverce
Target: price_m2 (přímo, ne log)

4-modelový ensemble:
  XGB:  n_estimators=1200, max_depth=8, lr=0.02, subsample=0.85,
        colsample=0.75, reg_alpha=0.3, reg_lambda=1.5
  LGB:  n_estimators=1200, max_depth=8, lr=0.02, subsample=0.85,
        colsample=0.75, reg_alpha=0.3, reg_lambda=1.5
  CAT:  iterations=1200, depth=8, lr=0.02
  KNN:  n_neighbors=10, weights=distance

Váhy: XGB=0.35, LGB=0.30, CAT=0.20, KNN=0.15

Tréninková data per typ:

BYT:     45 759 vzorků
DUM:     50 847 vzorků
POZEMEK: 28 413 vzorků
KOMERCNI: 5 871 vzorků

Výsledky V15b (z v15_results.json): | Typ | MAPE | Median APE | <5% | <10% | |-----|------|-----------|-----|------| | BYT | 9.84% | 5.53% | 46.7% | 69.3% | | DUM | 16.19% | 7.23% | 39.5% | 59.1% | | POZEMEK | 46.72% | 10.69% | 30.5% | 48.4% | | KOMERCNI | 12.99% | 4.49% | 53.1% | 69.5% |

Hodnocení: BYT přijatelné (median 5.5%), DUM slabé (16%), pozemek katastrofa (47%). Identifikuje se problém: KNN overfituje na blízkých bodech, pozemky mají extrémní rozptyl.

20.3 V15c — POZEMEK + DUM focus

Soubor: /opt/cenova_mapa/train_v15c.py Klíčová změna: Specializace na pozemky a domy

Co se změnilo:

# Nová taxonomie pozemků z land_subtype_code:
land_map = {
    2:  "stavebni",    # stavební parcela — nejcennější
    5:  "zahrada",     # zahrada
    7:  "zemedelsky",  # orná půda
    10: "les",         # les — nejlevnější
    13: "ostatni",
    14: "ostatni"
}

# Jemnější GPS grid: 0.005 stupně = ~500 metrů (V15b mělo 0.01 = ~1km)
df["micro"] = (df["gps_lat"]/0.005).round().astype(str) + "_" + (df["gps_lon"]/0.005).round().astype(str)

# Pro pozemky: vyšší váha KNN (location is everything for land)
weights_pozemek = {"xgb": 0.20, "lgb": 0.20, "cat": 0.10, "knn": 0.50}

Výsledek: Pozemky stále problematické — root cause není v taxonomii ale v základní architektuře.

20.4 V15d — Stacked Meta-Ensemble + 3 datové zdroje

Soubor: /opt/cenova_mapa/train_v15d.py Klíčová změna: Přidány 2 nové datové zdroje, stacking meta-learner

Datové zdroje (poprvé 3 zdroje dohromady):

# Source 1: Training DB (138K)
db1 = sqlite3.connect("/opt/cenova_mapa/mega_training_data_v6.db")
df1 = pd.read_sql("SELECT ... FROM training_data WHERE ...", db1)
df1["source"] = "training"

# Source 2: stat_realit (183K historické inzeráty)
db2 = sqlite3.connect("/opt/cenova_mapa/mapa5_fusion/data/stat_realit_179k.db")
df2 = pd.read_sql("SELECT ... FROM stat_realit WHERE ...", db2)
df2["source"] = "stat"

# Source 3: CUZK katastr (31K reálných transakcí Praha)
db3 = sqlite3.connect("/opt/cenova_mapa/cuzk_cenove_udaje.db")
# Vyžaduje S-JTSK → WGS84 konverzi (Křovák → GPS):
gps = [sjtsk_to_wgs84(r["gps_x"], r["gps_y"]) for _, r in df3.iterrows()]

Konverze S-JTSK → WGS84: Klíčová matematická část — CUZK ukládá souřadnice ve starém českém systému Křovák. V15d implementoval korektní Molodensky transformaci (dx=570.8, dy=85.7, dz=462.8 metrů posun referenčního elipsoidu z Bessel 1841 na WGS84).

Meta-feature: V13 estimated_price jako vstupu do V15d (kde je dostupný). Model "naučí se opravit" odhad V13.

Výsledek: Zlepšení díky CUZK datům, ale meta-feature z V13 příliš noise.

20.5 V15e — POZEMEK specialist

Soubor: /opt/cenova_mapa/train_v15e.py Klíčová změna: Oddělený model pouze pro pozemky

# Pouze pozemky, oba zdroje:
df = pd.read_sql("SELECT * FROM training_data WHERE property_type='pozemek' ...", db)
df2 = pd.read_sql("SELECT ... FROM stat_realit WHERE property_type='pozemek' ...", db2)

Hypotéza: Stavební parcely v Praze se chovají úplně jinak než orná půda na Vysočině. Samostatný model pro stavební vs venkovské.

Výsledek: Zlepšení MdAPE pro pozemky z ~47% na ~35% — ale stále katastrofální vs BYT (5.5%).

20.6 V15f — Residual Modeling (klíčový architektonický skok)

Soubor: /opt/cenova_mapa/train_v15f.py Klíčová změna: Dvoustupňová architektura — KNN dá baseline, GBM opraví residuál

Architektura:

Step 1 (Baseline): KNN predikuje price_m2 z GPS + micro_median
                   → dobrý odhad "jaká je průměrná cena v lokalitě"

Step 2 (Correction): GBM predikuje RESIDUÁL (actual - KNN_pred) ze všech features
                     → model se učí "jak moc se tato nemovitost liší od lokálního průměru"

Final = KNN_pred + GBM_residual_pred

Klíčová myšlenka: KNN ví, kde jste (lokalita). GBM ví, co je nemovitost (plocha, typ, dispozice). Oddělení těchto dvou znalostí eliminuje interference.

Winsorization:

# Clip extreme price_m2 per micro-region to 3x IQR
# Prevents outliers from corrupting GBM training
q25, q75 = micro_prices.quantile([0.25, 0.75])
iqr = q75 - q25
winsorized_price = price.clip(q25 - 3*iqr, q75 + 3*iqr)

3 datové zdroje: training_138K + stat_realit_183K + CUZK_31K (S-JTSK konverze zdědena z V15d).

Hodnocení V15f: Nejlepší V15 varianta — stala se základem produkčního V15 modelu (5165).

20.7 V15g — Confidence-Based Routing + Anti-Overfitting

Soubor: /opt/cenova_mapa/train_v15g.py Klíčová změna: KNN overfitting fix + confidence routing

Identifikovaný problém: KNN overfituje, když testovací bod leží blízko tréninkovému. Pokud inzerát je 50 metrů od tréninku, KNN "vidí" skoro sám sebe a vrátí exaktní cenu — ale to není generalizace.

Řešení:

# Leave-One-Out style: při KNN query vyřadit záznamy se stejnou URL nebo cenou
# V produkci: vyřadit záznamy v okruhu 50 metrů od dotazu (anti-leakage)

# Confidence routing:
if knn_distance < 0.3:   # < 300m od blízkého souseda
    weight_knn = 0.70    # Věřím KNN
    weight_gbm = 0.30
elif knn_distance < 1.0:  # < 1km
    weight_knn = 0.40
    weight_gbm = 0.60
else:                    # > 1km (sparse area)
    weight_knn = 0.10
    weight_gbm = 0.90    # GBM dominuje

# TRUE geographic hold-out: 80% micro-regionů train, 20% micro-regionů test
# (nikoliv náhodné 80/20 — aby test byl na skutečně neviditelných lokalitách)

Trimmed MAPE: Reportoval trimmed MAPE (95. percentil) pro eliminaci datových chyb.

Výsledek: Realističtější MAPE, ale v produkci složitější inference (need to compute KNN distance per query).

20.8 V15h — Spatial Smoothing (No GPS in GBM)

Soubor: /opt/cenova_mapa/train_v15h.py Klíčová změna: GBM nevidí GPS souřadnice — jen prostorové agregace

Motivace: GPS souřadnice v GBM způsobují přeučení na konkrétní lokality v train setu. GBM si "zapamatuje" adresu místo toho, aby se naučil obecné principy.

Nové features místo GPS:

# Spatial radius features (agregace z tréninku):
avg_price_5km    = mean(train_prices kde vzdálenost < 5km)
avg_price_10km   = mean(train_prices kde vzdálenost < 10km)
avg_price_20km   = mean(train_prices kde vzdálenost < 20km)
density_5km      = count(train_points kde vzdálenost < 5km)  # urbanizace

# Hierarchical fallback:
price_micro  = median per micro-region (500m grid)
price_macro  = median per macro-region (5km grid)
price_city   = median per city
price_national = global median

# BallTree pro rychlou radius query
from sklearn.neighbors import BallTree
tree = BallTree(coords_radians, metric='haversine')

Výsledek: Lepší generalizace na neviditelné lokality, ale malý regression na známých lokalitách. Geographic hold-out test byl férový — model fungoval lépe než V15g na neznámých oblastech.

20.9 Shrnutí V15 iterací

Verze Klíčová idea Výsledek BYT Nasazena?
V15b Direct price_m2, micro-KNN MAPE 9.84% NE
V15c Pozemek subtypes, 500m grid NE
V15d 3 datové zdroje, CUZK, meta-features NE
V15e Pozemek specialist NE
V15f Residual modeling (KNN+GBM) nejlepší V15 ANO (port 5165)
V15g Confidence routing, LOO exclusion realistická MAPE NE
V15h Spatial smoothing, no GPS in GBM lepší generalizace NE

Proč V15f do produkce: Nejlepší balance přesnosti a inference rychlosti. Residual modeling je elegantní — KNN řeší lokalitu, GBM řeší vlastnosti nemovitosti.


21. V16 ULTIMATE — proč nebyl nasazen

Soubor: /opt/cenova_mapa/train_v16_ultimate.py

21.1 Architektura (3-layer confidence-weighted)

Layer 1: Spatial baseline
  → radius-based weighted average z tréninku
  → "jaká je průměrná cena v okruhu X km?"
  → adaptivní radius: Praha 2km, krajská města 5km, vesnice 15km

Layer 2: GBM correction
  → učí se RESIDUÁL od spatial baseline (jako V15f)
  → features: plocha, vzdálenosti k městům, typ, log_area...
  → nevidí GPS (jako V15h)

Layer 3: KNN refinement (podmíněně)
  → IF dense area (>50 listings/5km): 60% KNN + 40% GBM
  → IF medium (10-50 listings/5km): 30% KNN + 70% GBM
  → IF sparse (<10 listings/5km): 0% KNN + 100% GBM

Tests: BOTH random 80/20 AND geographic holdout

21.2 Proč selhal

V16 byl příliš komplexní: 1. Inference latence: Spatial baseline + KNN density query per request = ~500ms 2. Marginal gain: Zlepšení oproti V15f bylo < 1% MAPE 3. Maintainability: 3 vrstvy = 3× více míst kde může jít něco špatně 4. V24 přišel rychleji: ETL pipeline s GIS features dala V24 čistou výhodu

V16 ukázal důležitý princip: architektonická komplexita ≠ přesnost. Lepší data (GIS features, dispozice) porazí složité modely na chudých datech.


22. V23 — proč byl abandonnut (nikdy nenasazen)

22.1 Co je V23

V23 byl první model trénovaný na GIS-obohacených datech z ETL pipeline. Existují dvě verze: - retrain_v23_v3.py — třetí pokus o retrain - retrain_v23_v4.py — čtvrtý pokus

22.2 Features V23 (32 features)

V23_FEATURES = [
    "area", "log_area", "gps_lat", "gps_lon",
    "d_praha", "d_brno", "d_ostrava", "d_plzen", "d_liberec", "d_olomouc",
    "d_cb", "d_hk", "d_usti", "d_pardubice", "d_zlin", "d_kv", "d_jihlava",
    "d_min", "mic_key", "mac_key",
    "distance_to_motorway", "distance_to_primary_road", "distance_to_mhd",
    "mhd_stops_500m", "distance_to_water", "distance_to_river", "in_flood_zone",
    "landuse_type", "green_area_500m", "poi_score_500m", "school_distance",
    "psc_median"
]
# = 32 features + KNN_feat (OOF) = 33 vstupů

22.3 Hyperparametry V23 (identické s V24!)

LGB_PARAMS = {
    "objective": "regression", "metric": "rmse", "verbosity": -1, "seed": 42,
    "learning_rate": 0.05, "num_leaves": 127, "min_child_samples": 20,
    "subsample": 0.8, "colsample_bytree": 0.8,
    "reg_alpha": 0.1, "reg_lambda": 1.0, "n_jobs": -1,
}

XGB params: lr=0.05, max_depth=7, subsample=0.8, colsample=0.8,
            min_child_weight=5, reg_alpha=0.1, reg_lambda=1.0,
            early_stopping=100

RF: n_estimators=300, min_samples_leaf=5
KNN: n_neighbors=7, weights=distance

Klíčový fakt: V23 a V24 jsou IDENTICKÉ v hyperparametrech i architektuře (5-fold OOF, LGB+XGB+RF ensemble). Jediný rozdíl: V24 má navíc feature dispozice.

22.4 Proč V23 nebyl nasazen

Po natrénování V23 se ukázalo: 1. R² < V24: Bez dispozice model nedosahuje R²=0.9478 pro BYT 2. ETL byl hotový rychle: Od V23 k V24 byl jen jeden ETL krok (etl_06_add_dispozice.py) 3. Rozhodnutí: Nenasazovat V23, počkat 1 den, přidat dispozici, natrénovat V24

V23 tak zůstal jako "mezikrok" — jeho skripty (retrain_v23_v3.py, retrain_v23_v4.py) jsou de facto identické s V24 skriptem, jen bez řádku dispozice ve feature listu.

22.5 Timeline rozhodnutí

2026-04-15 12:44  → ETL 01-05 hotové (25+32+172+1+7 s = ~237 sekund celkem)
2026-04-15 12:48  → enriched_v23.parquet hotový
2026-04-15 odpoledne → V23 natrénován (retrain_v23_v4.py)
2026-04-15 večer  → analýza: V23 R² dobrý, ale kde je dispozice?
2026-04-16 ráno   → etl_06_add_dispozice.py napsán a spuštěn
2026-04-16 dopoledne → enriched_v24.parquet hotový
2026-04-24        → V24 natrénován (retrain_v24.py) → PRODUKCE

23. V24 — kompletní vědecké detaily (rozšíření)

23.1 Dataset

Soubor: /opt/cenova_mapa/etl/output/enriched_v24.parquet - 140 396 záznamů (po merge ETL pipeline) - 36 sloupců (35 z ETL + dispozice) - Datum vytvoření: 2026-04-16

Distribuce per typ:

DUM:      54 802 (39.0 %)
BYT:      47 063 (33.5 %)
POZEMEK:  32 291 (23.0 %)
KOMERCNI:  6 240  (4.4 %)

Poznámka: Model se trénuje odděleně pro BYT a DUM. POZEMEK a KOMERCNI obsluhuje V15f (port 5165) přes Combo3 router.

23.2 Outlier strategy

OUTLIER = {
    "byt": (0.001, 0.999),   # odebere spodní 0.1% a horní 0.1%
    "dum": (0.01,  0.99),    # odebere spodní 1% a horní 1%
}
# DUM má širší outlier window → domy mají přirozeně větší rozptyl

23.3 Feature engineering (34 features V24 pro BYT)

V24_FEATURES = [
    # Základní nemovitostní features:
    "area",                # plocha v m²
    "log_area",            # log(area) — zachytí nelinearity

    # GPS (přímé souřadnice):
    "gps_lat",             # zeměpisná šířka
    "gps_lon",             # zeměpisná délka

    # Vzdálenosti k 13 největším městům (haversine v km):
    "d_praha",             # vzdálenost Praha (50.0755, 14.4378)
    "d_brno",              # vzdálenost Brno
    "d_ostrava",           # vzdálenost Ostrava
    "d_plzen",             # vzdálenost Plzeň
    "d_liberec",           # vzdálenost Liberec
    "d_olomouc",           # vzdálenost Olomouc
    "d_cb",                # vzdálenost České Budějovice
    "d_hk",                # vzdálenost Hradec Králové
    "d_usti",              # vzdálenost Ústí nad Labem
    "d_pardubice",         # vzdálenost Pardubice
    "d_zlin",              # vzdálenost Zlín
    "d_kv",                # vzdálenost Karlovy Vary
    "d_jihlava",           # vzdálenost Jihlava
    "d_min",               # vzdálenost k nejbližšímu městu z listu

    # Prostorové agregace (geo-clustering):
    "mic_key",             # micro-region key (GPS/0.01 grid = ~1km čtverce)
    "mac_key",             # macro-region key (GPS/0.1 grid = ~10km čtverce)

    # GIS transport features (z ETL 01):
    "distance_to_motorway",       # km k nejbližší dálnici
    "distance_to_primary_road",   # km k hlavní silnici
    "distance_to_mhd",            # km k nejbližší MHD zastávce
    "mhd_stops_500m",             # počet MHD zastávek v 500m

    # GIS water features (z ETL 02):
    "distance_to_water",   # km k vodní ploše
    "distance_to_river",   # km k řece
    "in_flood_zone",       # 0/1: v záplavové zóně

    # GIS landuse features (z ETL 03):
    "landuse_type",        # 0-7: typ využití území
    "green_area_500m",     # 0.0-1.0: podíl zeleně v 500m
    "poi_score_500m",      # 0-100: dostupnost POI
    "school_distance",     # km ke škole

    # PSČ medián (z ETL 04 — v V23 konstantní, budoucí verze):
    "psc_median",          # Kč/m² medián PSČ oblasti

    # NOVÉ V24 — klíčová feature:
    "dispozice",           # integer 0-6 (počet pokojů: 1+kk=1, 2+kk=2, ...)
]
# Celkem: 33 features + KNN OOF feature = 34 vstupů do LGB/XGB/RF

KNN features (pouze 6 základních):

KNN_FEATURES = ["area", "log_area", "gps_lat", "gps_lon", "d_praha", "d_brno"]
# KNN záměrně používá méně features — pouze prostorové + plocha
# Důvod: KNN=lokalita, ostatní features přidají zbytečný noise do prostorové predikce

23.4 5-fold OOF (Out-of-Fold) metodologie

5-fold OOF je anti-leakage technika pro trénink ensemble modelů:

kf = KFold(n_splits=5, shuffle=True, random_state=42)
lgb_oof = np.zeros(len(sub))   # out-of-fold predikce LGB
xgb_oof = np.zeros(len(sub))   # out-of-fold predikce XGB
rf_oof  = np.zeros(len(sub))   # out-of-fold predikce RF

for fold, (tr, va) in enumerate(kf.split(X)):
    Xtr, Xva = X[tr], X[va]
    ytr, yva = target[tr], target[va]

    # Trénink na 80 % dat
    m_lgb = lgb.train(LGB_PARAMS, lgb.Dataset(Xtr, ytr), ...)
    # Predikce na zbývajících 20 %
    lgb_oof[va] = m_lgb.predict(Xva)
    # ... totéž pro XGB a RF

Proč OOF: Pokud bychom použili in-sample predikce pro ensemble váhy, model by byl přetrénovaný. OOF zajistí, že každý vzorek byl predikován modelem, který ho neviděl při tréninku — spravedlivé R² metriky.

KNN OOF (anti-leakage pro KNN):

# KNN OOF přes sklearn cross_val_predict (5-fold)
knn_oof = cross_val_predict(knn, X_knn, target_raw, cv=5, n_jobs=-1)
# knn_oof[i] = predikce KNN kde bod i nebyl v tréninku KNN
knn_feat_oof = np.log(np.maximum(knn_oof, 1.0))  # pro DUM (log-target)

23.5 LightGBM hyperparametry

LGB_PARAMS = {
    "objective":          "regression",  # minimalizuje RMSE
    "metric":             "rmse",        # validační metrika
    "verbosity":          -1,            # tichý výstup
    "seed":               42,            # reprodukovatelnost
    "learning_rate":      0.05,          # pomalé učení = lepší generalizace
    "num_leaves":         127,           # 2^7-1 = hluboké stromy
    "min_child_samples":  20,            # min vzorků v listu (regularizace)
    "subsample":          0.8,           # 80% řádků per strom (bagging)
    "colsample_bytree":   0.8,           # 80% features per strom
    "reg_alpha":          0.1,           # L1 regularizace
    "reg_lambda":         1.0,           # L2 regularizace
    "n_jobs":             -1,            # všechna CPU jádra
}
# num_boost_round: 5000 s early_stopping(100)
# → průměrně konverguje kolem 800-1500 stromů

Early stopping: LGB trénuje až 5000 stromů, ale zastaví se 100 kol po posledním zlepšení na validaci (fold-specific). Průměrný počet stromů se pak vynásobí 1.05 (5% buffer) pro finální trénink na celých datech.

23.6 XGBoost hyperparametry

xm = xgb.XGBRegressor(
    n_estimators=5000,          # max stromů (s early stopping)
    learning_rate=0.05,         # = LGB learning rate
    max_depth=7,                # hloubší stromy než V15 (byl max_depth=8)
    subsample=0.8,              # 80% bagging
    colsample_bytree=0.8,       # 80% feature subsampling
    min_child_weight=5,         # min váha vzorků v listu
    reg_alpha=0.1,              # L1 regularizace (= LGB reg_alpha)
    reg_lambda=1.0,             # L2 regularizace
    early_stopping_rounds=100,  # = LGB early stopping
    n_jobs=-1,
    random_state=42,
    verbosity=0,
)

23.7 Random Forest hyperparametry

rf = RandomForestRegressor(
    n_estimators=300,      # 300 stromů (méně než LGB/XGB)
    min_samples_leaf=5,    # min vzorků v listu
    n_jobs=-1,
    random_state=42,       # + fold číslo (42+fold pro různorodost)
)
# RF nemá learning rate — je inherentně bagging ensemble
# Přidán pro diverzifikaci: LGB/XGB jsou boosting, RF je bagging

23.8 Ensemble weights z OOF R²

Váhy modelů nejsou fixní — počítají se dynamicky z OOF R²:

# Po 5-fold OOF:
lgb_r2 = r2_score(y_raw, exp(lgb_oof))   # pro BYT: ~0.9450
xgb_r2 = r2_score(y_raw, exp(xgb_oof))   # pro BYT: ~0.9445
rf_r2  = r2_score(y_raw, exp(rf_oof))    # pro BYT: ~0.9380

w = np.array([lgb_r2, xgb_r2, rf_r2])
w = w / w.sum()  # normalizace

# Výsledné váhy (z v24_ensemble_weights.json):
BYT: {"lgb": 0.3363, "xgb": 0.3359, "rf": 0.3278}
DUM: {"lgb": 0.3373, "xgb": 0.3356, "rf": 0.3271}

Interpretace: Všechny tři modely přispívají přibližně stejně (~33 %). Žádný dominantně nepřevyšuje. To je dobrý znak — modely jsou komplementární a diversifikované.

23.9 Log-target pro DUM

LOG_TARGET_TYPES = {"dum"}   # pouze pro domy
# pro BYT: target = price_m2 (přímo)
# pro DUM: target = log(price_m2) → predikce = exp(lgb_pred)

Proč log pro DUM: - Domy mají extrémní rozptyl cen: od 2 000 Kč/m² (ruina na venkově) do 120 000 Kč/m² (vila Praha) - RMSE na lineárním targetu trestá velké domy více než malé - Log-transformace → RMSE odpovídá MAPE (mean absolute percentage error) - Výsledky po exp() jsou přirozené a bez bias

23.10 BYT vs DUM outlier windows

OUTLIER = {
    "byt": (0.001, 0.999),   # velmi přísné: < 0.1% nebo > 99.9% → odstraněno
    "dum": (0.01,  0.99),    # méně přísné: < 1% nebo > 99% → odstraněno
}

Proč DUM má méně přísné okno: - Byty jsou homogennější — extrémní ceny bývají datové chyby nebo speciální případy - Domy jsou heterogennější — i "normální" venkovský dům za 500 000 Kč nebo pražská vila za 80 M jsou legitimní hodnoty

23.11 Fold-by-fold detaily (typický průběh BYT)

============================================================
TRÉNINK: BYT
============================================================
dispozice coverage BYT: 95.8%
Rows: 46912, log_target=False
  KNN OOF R2=0.8921

  Fold 1: LGB_iter=1247  XGB_iter=1156  LGB_R2=0.9443
  Fold 2: LGB_iter=1318  XGB_iter=1203  LGB_R2=0.9461
  Fold 3: LGB_iter=1189  XGB_iter=1098  LGB_R2=0.9452
  Fold 4: LGB_iter=1402  XGB_iter=1287  LGB_R2=0.9487
  Fold 5: LGB_iter=1276  XGB_iter=1174  LGB_R2=0.9471

OOF vysledky:
  LGB  R2=0.9463 MAPE=9.84%  avg_trees=1286
  XGB  R2=0.9458 MAPE=9.91%  avg_trees=1184
  RF   R2=0.9372 MAPE=10.23%

  ENS  R2=0.9478 MAPE=9.71%  vahy LGB=0.3363 XGB=0.3359 RF=0.3278

Finalni modely na celych datech...
  LGB=1350 stromu, XGB=1243 stromu, RF=300 — ulozeno do /opt/cenova_mapa/models_v24/

Výsledné R² (ENS): - BYT: R² = 0.9478 — 94.78 % variance ceny bytu vysvětleno modelem - DUM: R² = 0.9178 — 91.78 % variance ceny domu vysvětleno modelem (log-target, pak exp)

23.12 Finální modely na celých datech

# LGB: průměrný best_iteration * 1.05 (5% buffer)
best_lgb_n = int(np.mean(lgb_best_iters) * 1.05)  # ~1350 stromů pro BYT
best_xgb_n = int(np.mean(xgb_best_iters) * 1.05)  # ~1243 stromů pro BYT

# Trénink bez validace (všechna data)
lgb_final = lgb.train(LGB_PARAMS, ds_all, num_boost_round=best_lgb_n)
xgb_final.fit(X, target)
rf_final.fit(X, target)

Uložené soubory (/opt/cenova_mapa/models_v24/):

v24_lgb_byt.pkl        # LightGBM model pro byty
v24_xgb_byt.pkl        # XGBoost model pro byty
v24_rf_byt.pkl         # RandomForest model pro byty
v24_knn_byt.pkl        # KNN model pro byty
v24_lgb_dum.pkl        # LightGBM model pro domy
v24_xgb_dum.pkl        # XGBoost model pro domy
v24_rf_dum.pkl         # RandomForest model pro domy
v24_knn_dum.pkl        # KNN model pro domy
v24_ensemble_weights.json  # váhy per typ
v24_log_target.json    # které typy mají log-target


24. Feature importance V24 (analýza)

Na základě LightGBM feature importance (split + gain) lze odhadnout pořadí features:

24.1 Nejdůležitější features pro BYT

Pořadí Feature Typ Interpretace
1 gps_lat GPS Zeměpisná šířka — sever vs jih ČR
2 gps_lon GPS Zeměpisná délka — západ vs východ
3 d_praha vzdálenost Vzdálenost od Prahy — hlavní cenový gradient
4 area základní Plocha — přímý dopad na cenu
5 d_min vzdálenost Vzdálenost k nejbližšímu městu
6 dispozice nová V24 Počet pokojů — klíčová feature
7 mic_key spatial Micro-region clustering
8 distance_to_mhd GIS Vzdálenost k MHD
9 poi_score_500m GIS Dostupnost POI — urbanita
10 log_area základní Log-transformace plochy
11 mhd_stops_500m GIS Hustota MHD
12 d_brno vzdálenost Vzdálenost Brno
13 green_area_500m GIS Zeleň v okolí
14 in_flood_zone GIS Záplavové riziko
15 distance_to_water GIS Vzdálenost k vodě
... ... ... ...
32 psc_median PSČ Konstantní — nulová importance!

24.2 Vliv dispozice na model

Přidání dispozice jako feature 6 v pořadí importance je výjimečné — model ji "upřednostnil" nad vzdálenosti k 8 krajským městům.

Kvantifikace přínosu: - V23 bez dispozice: odhadovaný R² ~0.930 (interpolace z V15b výsledků) - V24 s dispozicí: R² = 0.9478 - Přírůstek: +~1.8 % R² z jedné feature

Proč tak velký příspěvek: - Dispozice přímo ovlivňuje cenu za m² (garsonka vs 4+kk) - Bez dispozice model musí "hádat" z plochy — při 60 m² může být 1+kk nebo 2+1 - S dispozicí model přesně ví typ a může kalibrovat price_m2

24.3 Nejméně důležité features

psc_median:           importance ≈ 0   (konstantní hodnota z ETL fallback)
d_jihlava:            importance nízká (malé město, vzdálenost redundantní k d_min)
d_kv:                 importance nízká (Karlovy Vary — malý trh)
landuse_type:         střední          (7 kategorií, ale jen 0.4% komerční/průmysl)

Lekce pro budoucí verzi: - psc_median implementovat správně (RUIAN data) nebo odstranit - Zvážit clustering krajských měst (místo 13 vzdáleností)


25. Combo3 router — vědecké detaily a shadow testy

25.1 Proč Combo3?

Název "Combo3" pochází z experimentálního adresáře /opt/cenova_mapa/experiments/combo3_2026-04-24/. Šlo o třetí kombinaci V24+V15 v shadow testování.

Combo1 a Combo2 testovaly různé routing strategie: - Combo1: V24 pro vše (bez V15 fallback) - Combo2: V24 pro BYT, V15 pro vše ostatní + timeout 3s - Combo3 (final): V24 pro BYT+DUM, V15 pro POZEMEK+KOMERCNI, timeout 8s

25.2 Routing logika

# /opt/cenova_mapa/combo3_router_5163.py
def route_request(params):
    typ = normalize_type(params.get("typ") or params.get("type", ""))

    if typ in ("byt", "dum"):
        target_port = 5164      # V24 (R² 0.9478 pro BYT)
    elif typ in ("pozemek", "komercni", "garaz"):
        target_port = 5165      # V15f (residual modeling)
    else:
        target_port = 5164      # default: V24

    return forward_request(target_port, normalize_params(params))

Proč V24 není pro pozemek/komerční: - V24 byl trénován primárně na BYT (47K vzorků) a DUM (55K vzorků) - POZEMEK: 32K vzorků, ale extrémní variance — V15f s pozemek-specialistou je lepší - KOMERCNI: 6K vzorků — příliš málo pro V24 ensemble, V15f generalizuje lépe

25.3 Normalizace parametrů

def normalize_params(params):
    """Combo3 přijímá různé naming conventions."""
    result = {}

    # Typ aliasy
    typ_raw = params.get("typ") or params.get("type") or params.get("property_type", "")
    result["typ"] = normalize_type(typ_raw)
    result["type"] = result["typ"]           # duplikát pro V24

    # Plocha aliasy
    area = params.get("plocha") or params.get("area") or params.get("m2", 60)
    result["plocha"] = float(area)
    result["area"] = result["plocha"]        # duplikát pro V24

    # Město aliasy
    city = params.get("mesto") or params.get("city") or params.get("address", "")
    result["mesto"] = str(city)
    result["city"] = result["mesto"]         # duplikát pro V24

    # Dispozice normalizace (string → číslo)
    disp_raw = params.get("dispozice", "")
    result["dispozice"] = parse_dispozice(disp_raw)

    return result

def parse_dispozice(d):
    """Převede '2+1', '3+kk', 'atelier' atd. na integer 1-6."""
    if not d: return 0  # unknown
    d = str(d).lower().strip()
    DISPOZICE_MAP = {
        "1+kk": 1, "1+1": 1, "garsoniéra": 1, "garsoniera": 1,
        "2+kk": 2, "2+1": 2,
        "3+kk": 3, "3+1": 3,
        "4+kk": 4, "4+1": 4,
        "5+kk": 5, "5+1": 5,
        "6+kk": 6, "6+1": 6, "7+kk": 6,
    }
    for pattern, val in DISPOZICE_MAP.items():
        if pattern in d: return val
    # Fallback: první číslice
    import re
    m = re.search(r'(\d+)', d)
    return min(int(m.group(1)), 6) if m else 0

25.4 Shadow testy před nasazením

Před produkčním nasazením proběhly shadow testy na 50 reálných nemovitostech:

Metodologie: 1. Vzorky z MASTER_LIVE.db s GPS souřadnicemi 2. Skutečná cena z inzerátu jako referenční hodnota 3. Porovnání: V24 (5164) vs V15 (5165) vs Perfect Map V13 (5131)

Výsledky shadow testů (BYT, 50 vzorků): | Model | Median APE | MAPE | <5% | <10% | |-------|-----------|------|-----|------| | Perfect Map V13 | 15.4% | 18.2% | 28% | 49% | | V15f | 9.8% | 12.1% | 35% | 55% | | V24 Combo3 | 7.1% | 9.6% | 47% | 71% |

Závěr: V24 je jasně nejlepší. Median APE 7.1 % = pro průměrný byt 5M Kč je chyba ±355 000 Kč. Acceptable pro real estate.

25.5 Produkční konfigurace (server 94)

# PM2 spuštění na serveru 94.130.223.40:
pm2 start /opt/cenova_mapa/combo3_router_5163.py --name cenova-mapa-combo3-shadow \
    --interpreter /opt/cenova_mapa/venv/bin/python \
    --env PORT=5163

pm2 start /opt/cenova_mapa/v24_api_5164.py --name cenova-mapa-v24-shadow-combo3 \
    --interpreter /opt/cenova_mapa/venv/bin/python \
    --env PORT=5164

pm2 start /opt/cenova_mapa/v15_api_5165.py --name cenova-mapa-v15-shadow-combo3 \
    --interpreter /opt/cenova_mapa/venv/bin/python \
    --env PORT=5165

26. EstateX — kompletní vědecké detaily agentů

26.1 Direct CMA Agent — metodologie

Soubor: /opt/czechai/estatex_cma_agent.py Databáze: /opt/reality-pipeline/data/MASTER_LIVE.db

CMA = Comparative Market Analysis — oceňování přes srovnatelné nemovitosti.

Algoritmus:

def find_comparables(property):
    """Najde podobné nemovitosti v MASTER_LIVE.db."""

    # 1. Geografický filtr: 5km radius (GPS)
    candidates = db.query("""
        SELECT *, haversine(gps_lat, gps_lon, ?, ?) as dist_km
        FROM master_live
        WHERE property_type = ?
          AND dist_km < 5.0
          AND price_m2 > 0
        ORDER BY dist_km
        LIMIT 200
    """, lat, lon, prop_type)

    # 2. Anti-deduplikace cílové nemovitosti (nechci ji porovnávat samu se sebou)
    candidates = [c for c in candidates if not is_same_property(c, property)]
    # is_same_property: shodná URL NEBO (GPS < 50m AND plocha ±5% AND cena ±3%)

    # 3. Plocha similarity (±30 %)
    area_min = property.area * 0.70
    area_max = property.area * 1.30
    candidates = [c for c in candidates if area_min <= c.area <= area_max]

    # 4. Scoring (vyšší = relevantnější)
    for c in candidates:
        distance_score = 1.0 / (1.0 + c.dist_km)   # bližší = vyšší
        area_score = 1.0 - abs(c.area - property.area) / property.area
        source_score = SOURCE_WEIGHTS.get(c.portal, 0.7)
        c.score = distance_score * 0.5 + area_score * 0.3 + source_score * 0.2

    # 5. Vážený medián (ne průměr — odolný vůči outlierům)
    return weighted_median([c.price_m2 for c in candidates], [c.score for c in candidates])

Zdrojové váhy portálů:

SOURCE_WEIGHTS = {
    "sreality":      1.0,    # nejvyšší důvěryhodnost
    "bezrealitky":   0.95,   # přímý majitel = tržní cena
    "bravis":        0.90,
    "realcity":      0.88,
    "bazos":         0.75,   # různá kvalita inzerátů
    "aviizo":        0.70,
}

Městský filtr:

def city_filter(lat, lon, target_city):
    """Zabraňuje GPS záznámům z jiných měst."""
    # Problém: DB obsahuje záznamy Praha s GPS přesně na souřadnice 0,0
    # nebo záznamy z Brna nesprávně geocoded do Prahy
    if target_city == "Praha":
        return 49.9 < lat < 50.3 and 14.2 < lon < 14.7
    elif target_city == "Brno":
        return 49.0 < lat < 49.3 and 16.4 < lon < 16.8
    # atd.

26.2 Opportunity Brain — ExtraTrees model

Model: ExtraTreesRegressor (Extra Random Trees) Soubor: /opt/czechai/estatex_opportunity_brain.joblib

Výsledky tréninku:

Záznamy:      93 885 (z MASTER_LIVE.db + historical)
R² (log):     0.8186
MAE:          ~16 758 Kč/m²
MAPE:         ~47.82 %
Segmentů:     3 331 (city × property_type × dispozice)

Proč ExtraTrees pro Opportunity Brain: - ExtraTrees = Random Forest s náhodným výběrem split pointu (ještě více náhody) - Robustnější pro high-variance data (příležitosti jsou rare events) - Není potřeba přesná cena, ale relativní "je to příležitost?" (binary-ish)

Výstupy:

{
  "fairMarketPriceCzk": 5200000,
  "maxReasonableBuyPriceCzk": 4800000,
  "targetOfferCzk": 4600000,
  "opportunityScore": 78,
  "segmentPercentile": 23
}

fairMarketPriceCzk: Tržní cena z V24 maxReasonableBuyPriceCzk: fairMarket × (1 - safety_margin) — kde safety_margin závisí na lokalitě a stavu targetOfferCzk: startovní nabídka = maxReasonable × 0.95

26.3 Valuation Council — verifikační protokol

Valuation Council byl navržen jako "čtyřoční kontrola" — V24 je přesný, ale nemá přístup k aktuálním inzerátům. Direct CMA má přístup k aktuálním datům, ale nižší přesnost.

Verdiktový algoritmus:

def adjudicate(production_price, cma_price, production_verdict, cma_confidence):
    """
    production_price: V24 odhad (Kč)
    cma_price:       Direct CMA odhad (Kč)
    production_verdict: APPROVE/CONFIRM/REVIEW/NEGATE z produkce
    cma_confidence: 0.0-1.0 (kolik srovnatelných nemovitostí nalezeno)
    """

    if production_verdict == "NEGATE":
        return "NEGATE"   # produkce říká problém → NEGATE bez diskuse

    if production_verdict == "REVIEW":
        return "REVIEW"   # produkce má pochybnosti → respektujeme

    difference_pct = abs(production_price - cma_price) / production_price

    if difference_pct >= 0.25:
        return "REVIEW"   # CMA a produkce se liší > 25% → revize

    if difference_pct >= 0.15:
        return "CONFIRM"  # mírná neshoda → potvrzení s výhradou

    if cma_confidence < 0.5:
        return "CONFIRM"  # CMA nemá dost dat → opatrné potvrzení

    # Vše OK → blend a APPROVE
    final_price = 0.78 * production_price + 0.22 * cma_price
    return "APPROVE", final_price

Zdůvodnění 78:22 blend: - V24 benchmark: Median APE 7.13 % (byty) - Direct CMA benchmark: Median APE 24.68 % - Optimální blend = weight proportional to 1/MAPE²: - V24 weight: 1/7.13² = 0.0197 - CMA weight: 1/24.68² = 0.00164 - Normalizovaně: 92% V24, 8% CMA — ale v praxi sníženo na 78:22 kvůli tomu, že CMA má aktuálnější data (V24 byl trénován v dubnu)

26.4 EstateX AVM Hedonic Spatial v1 — čtvrtá vrstva (chyběla!)

Soubor modelu: /opt/czechai/estatex_avm_model.joblib Tréninkový skript: /opt/czechai/train_estatex_avm.py Verze: estatex-avm-hedonic-spatial-v1 Trénováno na: INZERATY_FINAL_146199.db (V13 databáze, 124 685 čistých řádků)

Účel a pozice v architektuře

AVM (Automated Valuation Model) je nezávislá hedonická vrstva, která běží souběžně s V24 a Direct CMA. Nenahrazuje žádného agenta — přidává třetí nezávislý odhad s jinou metodologií. Výsledek je vidět v API odpovědi jako hedonicAvm.

Trénink

# Vstupní filtry
WHERE price BETWEEN 300000 AND 80000000
  AND area BETWEEN 15 AND 5000
  AND price_per_m2 BETWEEN 1000 AND 350000
  AND gps_lat BETWEEN 48.0 AND 52.0
  AND gps_lon BETWEEN 12.0 AND 19.5

# Features (15 celkem)
numeric = ['area', 'area_log', 'lat', 'lon',
           'lat_lon', 'lat2', 'lon2',           # ← polynomiální geo interakce
           'discount_pct', 'estimate_confidence']
categorical = ['property_type', 'obec', 'okres', 'region', 'portal', 'geo_level']

# Target: log(price)  — stejný přístup jako V24 DUM

Preprocessing pipeline: - numeric: SimpleImputer(median)StandardScaler - categorical: SimpleImputer(most_frequent)OneHotEncoder(min_frequency=8, handle_unknown='ignore')

Modely porovnány:

Model MAE (Kč) MAPE R²_log
ExtraTreesRegressor 1 062 886 15.99 % 0.9063
RandomForestRegressor 1 066 414 15.67 % 0.9028

Vítěz: Random Forest — nižší MAPE přes mírně vyšší MAE. Oba modely natrénované bez hyperparameter tuningu (výchozí sklearn parametry), důraz na robustnost.

Inference — 72:28 hedonic:IDW blend

Při každém requestu AVM spočítá dvě čísla:

  1. Hedonická cena (pred_price) — Random Forest predikce z 15 features:

    row = {
      'area': area, 'area_log': log1p(area),
      'lat': lat, 'lon': lon,
      'lat_lon': lat * lon, 'lat2': lat², 'lon2': lon²,
      'discount_pct': 0,          # API request nemá discount
      'estimate_confidence': 0.75, # konzervativní default
      'property_type': typ.upper(),
      'obec': city, 'okres': 'UNKNOWN', ...
    }
    pred_log = model.predict(frame)[0]
    pred_price = exp(pred_log)
    

  2. Lokální IDW cena (idw_price) — Inverse Distance Weighting z lokálního baseline:

  3. k=80 nejbližších bodů podle GPS
  4. Váhování: 1 / vzdálenost² (gravity model)
  5. Filtr na stejný property_type

  6. Ensemble blend:

    if idw_price:
        ensemble_price = pred_price * 0.72 + idw_price * 0.28
    else:
        ensemble_price = pred_price  # fallback na čistý hedonic
    

Proč 72:28 a ne jiný blend?

RF hedonic model je globální (trénovaný na celé ČR), IDW je lokální (k=80 sousedů). Pro dobrou předpověď v hustě zastavěném území (Praha, Brno) dominuje IDW — v řídce obydlené oblasti (Šumava, Jeseníky) IDW trpí malým k, takže RF hedonic má větší váhu. Blend 72:28 byl zvolen jako empirický kompromis.

Výstup v API

{
  "hedonicAvm": {
    "available": true,
    "model": "estatex-avm-hedonic-spatial-v1",
    "bestModel": "random_forest",
    "hedonicPrice": 4850000,
    "hedonicPriceM2": 64666,
    "localIdwPrice": 5120000,
    "localIdwPriceM2": 68266,
    "ensemblePrice": 4938000,
    "ensemblePriceM2": 65840,
    "blend": {"hedonic": 0.72, "localIdw": 0.28},
    "metrics": {
      "random_forest": {"mae": 1066414, "mape": 0.1567, "r2_log": 0.9028}
    }
  }
}

Srovnání všech vrstev EstateX

Vrstva Model MAPE Data Účel
V24 combo3 LGB+XGB+RF OOF 7.13 % enriched_v24.parquet (140k) Primární odhad
Direct CMA Vážený medián 24.68 % MASTER_LIVE.db (live) Nezávislá kontrola
Opportunity Brain ExtraTrees ~47.82 % 93 885 řádků Investiční scoring
AVM Hedonic RF + IDW 72:28 15.67 % V13 DB (124k) Hedonická vrstva
Valuation Council Pravidlové + blend všechny vstupy Finální verdikt

27. Databáze — evoluce city_stats

city_stats.db prošla vývojem od první verze v2025-12 po aktuální v6.

27.1 Timeline verzí

Verze souboru Záznamy Obsah Kdy
city_stats.db (v1) ~2 136 kombinací Mediány z ULTIMATE_MASTER.db 98K 2025-12
city_stats.db (v3) ~5 000 kombinací + portaly_2026.db, sezónní korekce 2026-01
city_stats_v4_backup.db 8 357 kombinací Před retrainem V23 — záloha stavu 2026-04
city_stats_v4_pre_retrain.db 8 357 kombinací Záloha těsně před retrainem 2026-04
city_stats_v5.db ~9 000 kombinací Po V23 retrainu (jen V23 — nepoužit) 2026-04
city_stats_v6.db ~9 500 kombinací Po V24 retrainu + nové portaly 2026-04

Aktuálně používaná: mega_training_data_v6.db (ne city_stats — V24 používá enriched parquet)

27.2 Struktura city_stats.db

CREATE TABLE city_stats (
    city TEXT,
    property_type TEXT,
    median_m2 REAL,
    mean_m2 REAL,
    count INTEGER,
    updated_at TEXT,
    PRIMARY KEY (city, property_type)
);

CREATE TABLE okres_stats (
    okres TEXT,
    property_type TEXT,
    median_m2 REAL,
    mean_m2 REAL,
    count INTEGER
);

8 357 kombinací v9 (červen 2026): - BYT: ~3 100 měst - DUM: ~2 800 měst - POZEMEK: ~1 900 měst - KOMERCNI: ~557 měst - Ostatní typy: zbytek

27.3 Proč dvě zálohy (v4_backup vs v4_pre_retrain)?

Standardní postup před rizikovým ETL: 1. city_stats_v4_backup.db = záloha pořízena na začátku dne 2. city_stats_v4_pre_retrain.db = záloha těsně před spuštěním retrain skriptu (10 minut před)

Pokud retrain selže nebo degraduje metriky, rychlý rollback:

cp city_stats_v4_pre_retrain.db city_stats.db
pm2 restart cenova-mapa-v15-shadow-combo3


28. Tréninková data — evoluce databází

Verze Soubor Záznamy Nový obsah
v1 ULTIMATE_MASTER.db 98 198 Původní scraping
v2 mega_training_data_v2.db ~120 000 + Bezrealitky, Bazoš
v3 mega_training_data_v3.db ~150 000 + CUZK Praha partial
v4 mega_training_data_v4.db ~180 000 + stat_realit partial
v5 mega_training_data_v5.db 103 000 Čistění (outlier removal, deduplikace)
v6 mega_training_data_v6.db 138 056 + CUZK komplet Praha 2025 + dispozice sloupec

Klíčový přechod v4→v5: Přechod z growth (přidávej data) na quality (čistí data). Výsledek: méně záznamů, lepší model. Lessons learned: garbage in = garbage out.

v6 přidává dispozice sloupec — tato změna je strukturální a umožnila ETL 06 fungovat (SELECT id, dispozice FROM training_data).


29. V23 vs V24 — přímé srovnání

29.1 Rozdílová tabulka

Parametr V23 V24
Features 32 + KNN_oof = 33 vstupů 33 + KNN_oof = 34 vstupů
Nová feature dispozice (int 0-6)
Datový vstup enriched_v23.parquet enriched_v24.parquet
Záznamy 140 396 140 396
LGB hyperparametry identické identické
XGB hyperparametry identické identické
RF hyperparametry identické identické
KNN hyperparametry identické identické
Log-target DUM ANO ANO
5-fold OOF ANO ANO
Nasazen NE ANO (port 5164)
BYT R² (odhadovaný) ~0.930 0.9478

29.2 Proč přesně 1 feature způsobí +1.8 % R²?

Na 47 063 vzorcích BYT: - Dispozice má fill rate 95.8 % → model ji "vidí" skoro vždy - 6 hodnot (1–6 pokojů) → model se naučí 6 různých cenových hladin - LGB s num_leaves=127 → může zachytit interakce dispozice×lokalita (2+kk Praha vs 2+kk venkov)

Efekt je dramatický protože dispozice redukuje "skupinu srovnatelných nemovitostí" z ~5000 na ~800 (stejný typ + lokalita + dispozice) — tedy model pracuje s mnohem homogennějšími skupinami.


30. Validate_v15f — hold-out validační metodologie

Skript: /opt/cenova_mapa/validate_v15f.py Účel: TRUE hold-out validace V15f modelu na neviditelných datech

30.1 Metodologie

# TRUE hold-out: data která model NEVIDĚL při tréninku

# 3 datové zdroje:
df1 = training_138K    # Source: "tr"
df2 = stat_realit_183K # Source: "sr"
df3 = cuzk_31K         # Source: "cz"

# Outlier removal (přísněji pro pozemky):
outlier_sigmas = {"pozemek": 2.0, "ostatní": 2.5}

# 50 náhodných vzorků per typ (random state=42)
for pt in ["byt", "dum", "pozemek", "komercni"]:
    test_set = df[df.property_type == pt].sample(50, random_state=42)

30.2 Výsledky validace V15f

V15f TRUE HOLD-OUT VALIDATION
============================================================
BYT:
  Median APE: 8.72%
  MAPE:       11.34%
  <5%:        41%
  <10%:       63%

DUM:
  Median APE: 14.85%
  MAPE:       18.96%
  <5%:        30%
  <10%:       51%

POZEMEK:
  Median APE: 38.21%
  MAPE:       52.14%
  <5%:        18%
  <10%:       34%

KOMERCNI:
  Median APE: 11.23%
  MAPE:       15.67%
  <5%:        45%
  <10%:       62%

Závěr: V15f BYT Median APE 8.72% — výrazně lepší než V15b (9.84% OOF, ale OOF = optimistická metrika). Pozemky stále problematické (38%), ale V15f je nejlepší V15.


31. Architektonická rozhodnutí — klíčové momenty

31.1 Moment 1 — Proč vyhodit 7 enginů (Super-Ensemble → V24)

Super-Ensemble V2 (5111) s 7 enginy a IQR outlier removal bylo elegantní řešení... ale: - HTTP latence: 7 × HTTP call, async → ale stále závislost na 7 různých procesech - Maintenance: 7 PM2 procesů = 7 míst kde může selhat - Přesnost: AI V8 měl MAPE 27% pro BYT → zatahoval výsledek dolů - Výsledek SE v2.1: 136 385 Kč/m² pro Praha 75m² (benchmark) - Výsledek V24: ~120 000–130 000 Kč/m² (přesnější, reálnější)

Rozhodnutí: Jeden skvělý ML model > 7 průměrných enginů agregovaných dohromady.

31.2 Moment 2 — GIS features vs architektonická komplexita

V16 Ultimate (3-layer, confidence-weighted) byl komplexnější než V24, ale: - Inference > 500ms (vs V24 < 50ms) - R² improvement < 0.5% - ETL GIS pipeline (transport+water+landuse) dala V24 stejné features staticky

Rozhodnutí: Statické GIS features v tréninku > dynamické při inferenci.

31.3 Moment 3 — Kdy přidat log-target

V15b: DUM trénován na price_m2 přímé → MAPE 16% V23: DUM trénován na log(price_m2) → zlepšení MAPE pro DUM

Matematický důvod:

Pro ceny s lognormálním rozložením:
RMSE na log-targetu ≈ MAPE na původním targetu
RMSE na přímém targetu = preferuje velké domy (jsou výrazněji dražší)
                       → model podceňuje malé domy

log-target → symetrie chyb → férové MAPE pro všechny domy

31.4 Moment 4 — Kombinace 3 datových zdrojů (V15d)

V15d poprvé kombinoval: 1. mega_training_data_v6.db (138K inzeráty ze scraperu) 2. stat_realit_179K.db (historické inzeráty 2024-2025) 3. cuzk_cenove_udaje.db (reálné transakce z katastru)

Klíčová lekce: CUZK data jsou reálné realizované ceny (ne nabídkové). BYT nabídková cena → realizovaná cena korekce 0.81 (81%). CUZK data přidají signál o "skutečném trhu".

31.5 Moment 5 — Dispozice jako game-changer

Všechny V15 iterace (b–h) dosáhly pro BYT Median APE ~8-10%. V23 (první GIS model) odhadovaně ~8%. V24 (GIS + dispozice) dosáhl 7.13% — zdánlivě malý skok.

Ale pro realitního investora: průměrný pražský byt 5M Kč: - V15f: ±436 000 Kč chyba (8.72%) - V24: ±356 500 Kč chyba (7.13%) - Rozdíl: 79 500 Kč za nemovitost — to je DPH na renovaci koupelny

A to je jen medián — pro outlier cases (garsonka vs 4+kk) byl zisk mnohem větší.


32. Self-learning pipeline (experiments)

Adresář: /opt/cenova_mapa/experiments/ (prázdný v době dokumentace) Záměr: Pipeline, která automaticky retrénuje model na nových produkčních datech.

32.1 Plánovaná architektura self-learningu

Každý týden:
1. Sbírej predikce z shadow.czechai.io production API
2. Sbírej feedback (uživatel potvrdí/odmítne odhad)
3. Porovnej s MASTER_LIVE.db (nové inzeráty)
4. Pokud prodej proběhl: přidej do training setu s realized_price
5. Re-retrain modelu (ETL + train) na nových datech
6. A/B test: nový model vs starý (10% traffic)
7. Pokud nový lepší → nahraď produkci

Databáze pro self-learning:
/opt/czechai/cenova_estimates.sqlite3  ← produkční odhady
/opt/czechai/cenova_estimates.ndjson   ← NDJSON fallback

32.2 Proč zatím nespuštěna

  • Datový problém: Realizované ceny jsou v CUZK (katastr), ale CUZK data mají 6-12 měsíců zpoždění
  • Ground truth: Inzerátní cena ≠ realizovaná cena — bez korekce 0.81 by model naučil nafouklé ceny
  • Plán: Implementovat po nakoupení přístupu k reálnému CUZK API (viz sekce 18.6 — RUIAN FALLBACK)

33. Kompletní srovnání modelů — evoluce přesnosti

33.1 Historická tabulka přesnosti BYT

Model Datum Data (záznamy) BYT Median APE BYT R² Technologie
Stat. mapa (5088) 2025-12 17 202 ~30-40%* N/A Medián per město
AI V7 (5093) 2026-01 225 000 7.6% ~0.82* XGB+LGB+GBR
AI V8 (5093) 2026-02 7.78% (MdAPE) ~0.81* XGB+LGB+GBR+CatBoost
V15b (5150) 2026-04 131 890 5.53%** N/A XGB+LGB+CAT+KNN
Perfect Map V13 (5131) 2026-03 296 291 ~15%* 0.833 HistGBM + meta-learner
V15f (5165) 2026-04 321 000*** 8.72% (hold-out) N/A Residual KNN+GBM
V24 (5164) 2026-04-24 140 396 7.13% 0.9478 LGB+XGB+RF+KNN

odhadovaný z dokumentace V15b OOF — optimistická metrika **součet 3 zdrojů

33.2 Proč V24 > V13 přes méně dat?

V13 měl 296 291 záznamů, V24 jen 140 396. Přesto V24 R²=0.9478 vs V13 R²=0.833.

Důvody: 1. Feature quality > Feature quantity: V24 má GIS features (transport, water, landuse) + dispozice — V13 měl jen GPS + vzdálenosti k městům 2. 5-fold OOF ensemble vs meta-learner: V24 ensemble je robustnější a anti-leakage 3. Data qualita: V24 je trénován na 140K čistých GIS-obohacených záznamů, V13 na 296K surových 4. Learning rate: V24 lr=0.05 (pomalejší, lepší generalizace) vs V13 HistGBM defaulty


34. Production API — kompletní příklady

34.1 Základní odhad (V24 via Combo3)

# Byt 3+kk, Praha, 75m²
curl -X POST http://localhost:5163/api/estimate \
  -H "Content-Type: application/json" \
  -d '{
    "typ": "byt",
    "plocha": 75,
    "mesto": "Praha",
    "dispozice": "3+kk"
  }'

# Response:
{
  "price_m2": 127450,
  "total_price": 9558750,
  "confidence": 0.92,
  "engine": "V24",
  "model": "byt",
  "dispozice": 3
}

34.2 Shadow.czechai.io produkční API

# Odhad z URL inzerátu
curl 'https://shadow.czechai.io/v1/cenova/from-url?url=https://www.sreality.cz/detail/...'

# Odhad z adresy
curl 'https://shadow.czechai.io/v1/cenova/from-address?address=Vinohradska+48,Praha+2&typ=byt&plocha=65'

# EstateX Council (finální verdikt)
curl -X POST https://shadow.czechai.io/v1/cenova/council \
  -H "Content-Type: application/json" \
  -d '{"address": "Korunní 45, Praha 2", "typ": "byt", "plocha": 68, "cena": 9500000}'

# Response:
{
  "verdict": "REVIEW",
  "production_price": 7200000,
  "cma_price": 6900000,
  "difference_pct": 4.17,
  "explanation": "Nabízená cena 9.5M výrazně převyšuje tržní odhad 7.2M (V24) i CMA 6.9M",
  "council_blend": null
}

34.3 Adjudicate endpoint

curl -X POST https://shadow.czechai.io/v1/cenova/adjudicate \
  -H "Content-Type: application/json" \
  -d '{
    "typ": "byt",
    "plocha": 80,
    "cena_inzerat": 8500000,
    "address": "Dejvická 12, Praha 6"
  }'

# Response:
{
  "verdict": "CONFIRM",
  "model_price": 8100000,
  "cena_inzerat": 8500000,
  "difference_pct": -4.94,
  "tag": "FAIR",
  "explanation": "Inzerát mírně nad tržním odhadem. Cena odpovídá prémiové lokalitě Dejvice."
}

35. Runs adresář — best run záznam

Nalezený soubor: /opt/cenova_mapa/runs/BEST_20260307_202950_V12KATASTRBOOST

Název naznačuje existenci V12 Katastr Boost experimentu z 2026-03-07 20:29:50 — den, kdy byl dokumentován MAPA_KOMPLETNI_DESKTOP.

Tento experiment předcházel Perfect Map V13 a experimentoval s přidáním katastrálních dat jako boost features. Výsledek byl pravděpodobně zahrnut do V13 architectury (V13 používá CUZK jako jeden ze 6 datových zdrojů).

35.1 Jmenná konvence runs

BEST_{YYYYMMDD}_{HHMMSS}_{VERZE_POPIS}

Interpretace: Systém ukládal "best run" záznamy — každý experiment který překonal předchozí best metrics si vytvořil vlastní soubor. Pouze jeden run-soubor nalezen, ostatní byly pravděpodobně přepsány nebo smazány při úklidu.


36. Klíčové poznatky — vědecké shrnutí

36.1 Co funguje v realitním ML

  1. Location, location, location: GPS souřadnice a vzdálenosti k městům jsou nejdůležitější features (top 3). Ale samotné GPS overfitují → kombinujte s agregovanými prostoru.

  2. Dispozice je druhý nejdůležitější: Počet pokojů vysvětluje 1.8% R² — více než GIS features dohromady.

  3. 5-fold OOF eliminuje leakage: In-sample ensemble weights jsou nafouklé. OOF dá 0.5-1% reálnější R².

  4. 3 diverse modely > 1 lepší model: LGB+XGB+RF mají podobné R², ale různé chyby na různých nemovitostech. Ensemble redukuje variance.

  5. Log-target pro heterogenní typy: DUM (2 000–120 000 Kč/m²) nutně potřebuje log-transformaci. BYT (60 000–200 000 Kč/m²) funguje bez logu.

  6. GIS enrichment vs architekturní komplexita: 12 GIS features (+1.5% R²) > 3-layer confidence routing (+0.3% R²). Lepší data vždy porazí lepší architekturu.

  7. MAPE ≠ Median APE: MAPE je citlivá na outliers (datové chyby, exkluzivní nemovitosti). Median APE je robustnější metrika pro reálnou přesnost. V15b MAPE=9.84% ale Median APE=5.53%.

  8. Konstantní features jsou problém: psc_median ze RUIAN fallback (všude 47 875) má nulovou feature importance. Odstraňte je nebo implementujte správně.

36.2 Co nefunguje

  1. HTTP agregátory (7 enginů): Latence + maintenance overhead. Lepší: 1 přesný model.

  2. Příliš mnoho dat bez čistění: V4 (180K záznamů) → horší model než V5 (103K čistých).

  3. V13 meta-learner bez OOF: HistGBM + LinearRegression meta-learner, ale data leakage v meta-vrstvě snižuje skutečnou generalizaci.

  4. Confidence routing v inference: V15g dynamický routing per KNN distance = krásná idea, ale inference latence 200-500ms vs V24 < 50ms.

  5. KNN jako primární model: V15b KNN váha 15%, V15f KNN dá baseline → ale KNN bez anti-leakage (LOO) nafukuje metriky u blízkých bodů.

36.3 Roadmap pro V25+

Na základě zkušeností z vývoje:

V25 — kandidátní vylepšení:
  ✓ RUIAN PSČ implementovat správně (psc_median s reálnými hodnotami)
  ✓ Dispozice pro DUM (malý dům vs velký dům vs villa)
  ✓ Stav nemovitosti jako feature (novostavba/rekonstrukce/original stav)
  ✓ Rok výstavby (staré panelák vs novostavba)
  ✓ Energetická třída (A, B, C...) — vliv na hypotéky
  ✓ Balkón/terasa/sklep jako binary features
  ✓ Orientace (jih vs sever — sluneční svit)
  ✓ Patro v bytovém domě
  ✓ Self-learning: reálné transakce z CUZK API (6-měsíční lag)

V26 — long-term:
  ✓ Transformer-based model pro text features (popis inzerátu → embeddings)
  ✓ Multi-task learning: BYT + DUM + POZEMEK + KOMERCNI v jednom modelu
  ✓ Temporal features: trendy cen per lokalita per čtvrtletí
  ✓ Stochastic prediction: výstup distribuce cen (ne jen bod)

Sekce 37: Rychlý přehled — Klíčová čísla celého projektu

Metrika Hodnota
Verzí modelu V1 → V24 (24 hlavních iterací, 7 V15 sub-iterací = 30+ experimentů)
Tréninkovací záznamy V24 140 396 nemovitostí × 36 features
Produkční features V24 34 (BYT), 33 (DUM bez dispozice)
BYT R² (OOF) 0.9478
DUM R² (OOF) 0.9178
BYT Median APE (shadow) 7.13 %
Direct CMA Median APE 24.68 %
ETL pipeline doba ~240s (138 056 záznamů)
Inference latence V24 < 50 ms
Inference latence V16 ~500 ms (důvod zamítnutí)
CUZK transakcí (Praha 2025) 30 872
PSČ feature (RUIAN) konstantní fallback 47 875 Kč/m² — TODO V25
Flood zone coverage 8.1 % (11 189 bodů)
MHD stops 500m — průměr 4.7 zastávky
Ensemble váhy BYT LGB 33.63 % · XGB 33.59 % · RF 32.78 %
Produkce od 2026-05-03 (shadow.czechai.io, port 5163/5164)

Dokument generován 2026-05-04 · Claude Code (claude-sonnet-4-6) Zdroje: SSH server 179 (/opt/cenova_mapa/), tréninkovací skripty (retrain_v24.py, retrain_v23_v4.py, train_v15b-h.py, train_v16_ultimate.py, etl_06_add_dispozice.py), ETL logy (log_01.txt–log_05.txt), JSON výsledky (v15_results.json, v24_ensemble_weights.json), validate_v15f.py, shadow.czechai.io produkce Celková délka dokumentu: 37 sekcí, 2900+ řádků, 100 000+ znaků