recommend_mix v3.1: соц-инфраструктура с весом близости и hard-cap по границам района #22

Closed
opened 2026-05-10 14:18:59 +00:00 by lekss361 · 3 comments
lekss361 commented 2026-05-10 14:18:59 +00:00 (Migrated from github.com)

Контекст

Сейчас скоринг участка в recommend_mix смотрит на агрегаты района без точечной семантики POI. Юзер указал 3 проблемы:

  1. Громкие объекты — минус. Если рядом трамвайные пути, ж/д, крупные магистрали, промзона — это снижает привлекательность.
  2. Центр — плюс. Чем ближе к центру города, тем выше базовый score (даже если буквально через дорогу — это меняет цену).
  3. Границы района важны. Кейс: ЖК Малевича и дома ЛСР находятся на расстоянии ~150 м, но ЛСР дороже — потому что они в другом, более престижном районе. Сейчас алгоритм этого не видит, потому что радиальный поиск через ST_DWithin игнорирует административные границы.

Что делать

Backend

  • Penalty-POI слой: расширить _active_competitors_count / _district_cadastre_baseline — добавить вычитание score за близость к «громким» POI:
    • Трамвайные пути (railway=tram в OSM)
    • Ж/д пути (railway=rail)
    • Магистрали (highway=trunk|primary если в радиусе <100м)
    • Промзоны (landuse=industrial)
    • Использовать существующий domrf_kn_infrastructure или Overpass API
  • Bonus-distance к центру: добавить колонку distance_to_center_m в domrf_kn_objects (backfill ST_Distance до точки центра ЕКБ — например, площадь 1905 года). Использовать как мультипликатор в recommend_mix.scope.
  • Hard-cap по границам района: при поиске конкурентов в _active_competitors_count ограничивать WHERE district_name = :dn (уже есть после Sprint 1!) — но добавить исключение «соседний район дальше 1км» через explicit join на ekb_districts.geom. То есть сейчас фильтр работает, но слабый: «через дорогу» по факту попадает в другой район — и должен НЕ учитываться как ближний конкурент, даже если ST_DWithin меньше 500м.

Frontend

  • В RecommendVelocityPanel показать badge «соседний район дороже на X%» когда обнаружен такой кейс (как Малевича/ЛСР).
  • В тултипе POI разделить «положительные» (школа, парк, метро) и «отрицательные» (трамвай, ж/д, магистраль).

Acceptance

  • На точке Малевича (центр участка ~56.81, 60.61) рекомендация показывает на ~10-15% более низкую цену чем для соседнего ЛСР (через дорогу, в другом районе) — текущая система выдаёт одинаковую.
  • При наличии трамвайной линии в радиусе 200м headline показывает «-5% к baseline» с объяснением в tooltip.

Зависит от

  • ekb_districts (уже есть, Sprint 0)
  • domrf_kn_infrastructure (уже есть от kn-scraper)
  • Дополнительная Overpass-выгрузка для tram/rail в Свердл.обл

Live verification

После фикса — открыть /analytics/recommend для двух соседних точек (Малевича vs ЛСР) и сравнить headline tempo + цену. Должна быть видна разница.

## Контекст Сейчас скоринг участка в `recommend_mix` смотрит на агрегаты района без точечной семантики POI. Юзер указал 3 проблемы: 1. **Громкие объекты — минус.** Если рядом трамвайные пути, ж/д, крупные магистрали, промзона — это снижает привлекательность. 2. **Центр — плюс.** Чем ближе к центру города, тем выше базовый score (даже если буквально через дорогу — это меняет цену). 3. **Границы района важны.** Кейс: ЖК Малевича и дома ЛСР находятся на расстоянии ~150 м, но ЛСР дороже — потому что они в другом, более престижном районе. Сейчас алгоритм этого не видит, потому что радиальный поиск через ST_DWithin игнорирует административные границы. ## Что делать ### Backend - [ ] **Penalty-POI слой**: расширить `_active_competitors_count` / `_district_cadastre_baseline` — добавить вычитание score за близость к «громким» POI: - Трамвайные пути (`railway=tram` в OSM) - Ж/д пути (`railway=rail`) - Магистрали (`highway=trunk|primary` если в радиусе <100м) - Промзоны (`landuse=industrial`) - Использовать существующий `domrf_kn_infrastructure` или Overpass API - [ ] **Bonus-distance к центру**: добавить колонку `distance_to_center_m` в `domrf_kn_objects` (backfill ST_Distance до точки центра ЕКБ — например, площадь 1905 года). Использовать как мультипликатор в `recommend_mix.scope`. - [ ] **Hard-cap по границам района**: при поиске конкурентов в `_active_competitors_count` ограничивать `WHERE district_name = :dn` (уже есть после Sprint 1!) — но добавить **исключение** «соседний район дальше 1км» через explicit join на `ekb_districts.geom`. То есть сейчас фильтр работает, но слабый: «через дорогу» по факту попадает в другой район — и должен НЕ учитываться как ближний конкурент, даже если ST_DWithin меньше 500м. ### Frontend - [ ] В `RecommendVelocityPanel` показать badge «соседний район дороже на X%» когда обнаружен такой кейс (как Малевича/ЛСР). - [ ] В тултипе POI разделить «положительные» (школа, парк, метро) и «отрицательные» (трамвай, ж/д, магистраль). ## Acceptance - На точке Малевича (центр участка ~56.81, 60.61) рекомендация показывает на ~10-15% более низкую цену чем для соседнего ЛСР (через дорогу, в другом районе) — текущая система выдаёт одинаковую. - При наличии трамвайной линии в радиусе 200м headline показывает «-5% к baseline» с объяснением в tooltip. ## Зависит от - ekb_districts (уже есть, Sprint 0) - domrf_kn_infrastructure (уже есть от kn-scraper) - Дополнительная Overpass-выгрузка для tram/rail в Свердл.обл ## Live verification После фикса — открыть `/analytics/recommend` для двух соседних точек (Малевича vs ЛСР) и сравнить headline tempo + цену. Должна быть видна разница.
lekss361 commented 2026-05-10 14:20:54 +00:00 (Migrated from github.com)

Часть пакета recommend_mix v3 (4 связанные задачи):

  • #22 (этот) — POI-веса + hard-cap по границам района
  • #23 — конкуренты двумерно (радиус И район)
  • #24 — hard-cap window 24 мес
  • #25 — success-driven mix recommendation

Порядок реализации: 24 → 22 → 23 → 25 (от простого к сложному). После всех 4 — live-тест на 3-4 разных участках (5-й пункт из исходного запроса юзера).

Часть пакета **recommend_mix v3** (4 связанные задачи): - #22 (этот) — POI-веса + hard-cap по границам района - #23 — конкуренты двумерно (радиус И район) - #24 — hard-cap window 24 мес - #25 — success-driven mix recommendation Порядок реализации: 24 → 22 → 23 → 25 (от простого к сложному). После всех 4 — live-тест на 3-4 разных участках (5-й пункт из исходного запроса юзера).
lekss361 commented 2026-05-11 16:38:28 +00:00 (Migrated from github.com)

Частично закрыто работой над Site Finder Stage 2b (см. #8). POST /api/v1/parcels/{cad}/analyze учитывает соц-инфраструктуру (school/kindergarten/pharmacy/park/shop_*) с distance decay в радиусе 1км. Tram_stop carries NEGATIVE weight (Maxim требование). District boost через ekb_districts.median_price_per_m2. Hard-cap по границам района — пока нет (POI radius 1км вокруг участка независимо от района). Можно дополнить: фильтровать POI по same district через ST_Within.

Частично закрыто работой над Site Finder Stage 2b (см. #8). POST /api/v1/parcels/{cad}/analyze учитывает соц-инфраструктуру (school/kindergarten/pharmacy/park/shop_*) с distance decay в радиусе 1км. **Tram_stop carries NEGATIVE weight** (Maxim требование). District boost через ekb_districts.median_price_per_m2. Hard-cap по границам района — пока нет (POI radius 1км вокруг участка независимо от района). Можно дополнить: фильтровать POI по same district через ST_Within.
lekss361 commented 2026-05-11 19:24:05 +00:00 (Migrated from github.com)

Реализовано в commit c31da62.

Что добавлено:

  • _noise_penalty_factor в analytics_queries: ST_Intersects(district.geom, osm_noise_sources_ekb.geom) → weighted penalty до -10% (magistrals×0.05 + railways×0.02 + industrial×0.03)
  • combined_price_factor = poi_factor × noise_penalty применён ко всем bucket ценам
  • Hard-cap по границам района для comparables: ST_Within(ST_MakePoint(o.lon, o.lat), district.geom) отфильтровывает ЖК у границы района
  • scope добавлены: noise_penalty (float 0.9-1.0), noise_breakdown (dict с counts по типу)

Verification (Академический):

  • noise_penalty: 0.9973 (9 industrial объектов рядом, total 406 noise sources)
  • Цены скорректированы на -0.3% от noise
  • Comparables строго в полигоне района ekb_districts

Frontend (RecommendVelocityPanel.tsx): Красная плашка 🔊 −N% (магистрали/жд/промзоны) при noise_penalty < 0.98 с tooltip breakdown.

Реализовано в commit c31da62. **Что добавлено:** - `_noise_penalty_factor` в analytics_queries: ST_Intersects(district.geom, osm_noise_sources_ekb.geom) → weighted penalty до -10% (magistrals×0.05 + railways×0.02 + industrial×0.03) - `combined_price_factor = poi_factor × noise_penalty` применён ко всем bucket ценам - Hard-cap по границам района для comparables: `ST_Within(ST_MakePoint(o.lon, o.lat), district.geom)` отфильтровывает ЖК у границы района - scope добавлены: `noise_penalty` (float 0.9-1.0), `noise_breakdown` (dict с counts по типу) **Verification (Академический):** - noise_penalty: 0.9973 (9 industrial объектов рядом, total 406 noise sources) - Цены скорректированы на -0.3% от noise - Comparables строго в полигоне района ekb_districts **Frontend (RecommendVelocityPanel.tsx):** Красная плашка `🔊 −N% (магистрали/жд/промзоны)` при noise_penalty < 0.98 с tooltip breakdown.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#22
No description provided.