recommend_mix v3.4: success-driven mix — рекомендация на базе 'что хорошо продавалось' #25

Closed
opened 2026-05-10 14:20:32 +00:00 by lekss361 · 2 comments
lekss361 commented 2026-05-10 14:20:32 +00:00 (Migrated from github.com)

Контекст

Сейчас recommend_mix рекомендует mix на основе средних метрик района (доли студий/1к/2к/3к, средние цены) — но не различает «продаваемое успешно» vs «продаваемое плохо». Юзер указал что нужно идти от успеха в выборке:

  • Какая квартирография в районе X продавалась быстрее?
  • Какая давала более высокую цену за м²?
  • Какая имела меньшую среднюю площадь при той же цене (= лучшая удельная маржа)?

И учитывать это при рекомендации. Юзер заранее предупреждает что «будут множество но» — то есть это итеративная фича, не финальный рецепт. Поэтому делаем v1 с понятными метриками и оставляем место для калибровки.

Что делать

Backend

  • Новая таблица/view v_bucket_success_score per (район × класс × room_bucket) с полями:
    • avg_velocity_kvm_per_month (средняя скорость продажи в bucket)
    • avg_price_per_m2 (средняя цена)
    • avg_area_m2 (средняя площадь — меньше = выше удельная маржа)
    • n_deals (статистическая значимость)
    • success_score = composite: velocity_z * 0.5 + price_z * 0.3 + (-area_z) * 0.2 (z-scores normalised по району-классу)
  • В recommend_mix.scope отдавать success_ranking: list[bucket] — sorted desc by score.
  • Скорректировать рекомендуемый mix: если bucket имеет высокий success_score (топ-3 по району), его доля увеличивается относительно baseline-районной структуры (на 5-15% — не радикально).
  • Фильтр «но»: если bucket success_score высокий но n_deals < 30 — не учитывать (статистически недостоверно).

Frontend

  • В RecommendMixTable добавить колонку «Топ-bucket в районе» — звёздочка/бейдж для тех, кто в топ-3 по success_score.
  • Tooltip объясняющий что считается «успешным» (быстрая продажа + высокая цена + меньшая площадь).
  • В headline текст: «Рекомендация смещена в пользу [bucket X] — этот размер показал лучшую динамику в районе за последние 24 мес».

Acceptance

  • Для Академического Comfort: топ-3 success_score должны соответствовать здравому смыслу (вероятно 1к-2к компактные, не 3-4к).
  • Recommended mix отличается от baseline-структуры района: студии или 1к должны иметь долю на 5-15% выше «как у всех».
  • Видна явная связь «выбранный mix → его success_score» в UI.

Зависит от

  • v3.3 (#TBD) hard-cap 24mo
  • domrf_kn_sale_graph (есть)
  • Возможно Objective lots_pf после применения schema 68 — даст ещё более точные registration_date per flat для velocity по bucket

Live verification (5-й пункт юзера)

После сборки v3.1-3.4 — открыть /analytics/recommend для 3-4 разных участков и сравнить рекомендации с реальными «бестселлерами» в этих районах (Академический comfort, Втузгородок standart, Уралмаш comfort, центр business). Юзер хочет «по живому понять как это работает» — это именно про этот пункт.

Будущие "но" (не для v1, фиксируем)

  • Нормировка по сезонности (mass-class в августе продаётся хуже)
  • Учёт типа покупателя (Objective.bank_name — ипотечники vs cash)
  • Cross-район influence (если соседний район «перегрет» — bucket мог быть успешен из-за overflow)
  • Учёт стадии стройки (новостройки на котловане vs готовый дом — разная velocity)
## Контекст Сейчас `recommend_mix` рекомендует mix на основе **средних метрик района** (доли студий/1к/2к/3к, средние цены) — но не различает «продаваемое успешно» vs «продаваемое плохо». Юзер указал что нужно идти от **успеха в выборке**: - Какая квартирография в районе X **продавалась быстрее**? - Какая давала **более высокую цену за м²**? - Какая имела **меньшую среднюю площадь** при той же цене (= лучшая удельная маржа)? И учитывать это при рекомендации. Юзер заранее предупреждает что **«будут множество но»** — то есть это итеративная фича, не финальный рецепт. Поэтому делаем v1 с понятными метриками и оставляем место для калибровки. ## Что делать ### Backend - [ ] Новая таблица/view `v_bucket_success_score` per (район × класс × room_bucket) с полями: - `avg_velocity_kvm_per_month` (средняя скорость продажи в bucket) - `avg_price_per_m2` (средняя цена) - `avg_area_m2` (средняя площадь — меньше = выше удельная маржа) - `n_deals` (статистическая значимость) - `success_score` = composite: `velocity_z * 0.5 + price_z * 0.3 + (-area_z) * 0.2` (z-scores normalised по району-классу) - [ ] В `recommend_mix.scope` отдавать `success_ranking: list[bucket]` — sorted desc by score. - [ ] Скорректировать рекомендуемый mix: если bucket имеет высокий success_score (топ-3 по району), его доля **увеличивается** относительно baseline-районной структуры (на 5-15% — не радикально). - [ ] **Фильтр «но»**: если bucket success_score высокий но n_deals < 30 — не учитывать (статистически недостоверно). ### Frontend - [ ] В `RecommendMixTable` добавить колонку «Топ-bucket в районе» — звёздочка/бейдж для тех, кто в топ-3 по success_score. - [ ] Tooltip объясняющий что считается «успешным» (быстрая продажа + высокая цена + меньшая площадь). - [ ] В headline текст: «Рекомендация смещена в пользу [bucket X] — этот размер показал лучшую динамику в районе за последние 24 мес». ## Acceptance - Для Академического Comfort: топ-3 success_score должны соответствовать здравому смыслу (вероятно 1к-2к компактные, не 3-4к). - Recommended mix отличается от baseline-структуры района: студии или 1к должны иметь долю на 5-15% выше «как у всех». - Видна явная связь «выбранный mix → его success_score» в UI. ## Зависит от - v3.3 (#TBD) hard-cap 24mo - domrf_kn_sale_graph (есть) - Возможно Objective lots_pf после применения schema 68 — даст ещё более точные `registration_date` per flat для velocity по bucket ## Live verification (5-й пункт юзера) **После сборки v3.1-3.4 — открыть `/analytics/recommend` для 3-4 разных участков и сравнить рекомендации с реальными «бестселлерами» в этих районах** (Академический comfort, Втузгородок standart, Уралмаш comfort, центр business). Юзер хочет «по живому понять как это работает» — это именно про этот пункт. ## Будущие "но" (не для v1, фиксируем) - Нормировка по сезонности (mass-class в августе продаётся хуже) - Учёт типа покупателя (Objective.bank_name — ипотечники vs cash) - Cross-район influence (если соседний район «перегрет» — bucket мог быть успешен из-за overflow) - Учёт стадии стройки (новостройки на котловане vs готовый дом — разная velocity)
lekss361 commented 2026-05-10 14:21:01 +00:00 (Migrated from github.com)

Часть пакета recommend_mix v3: см. #22 #23 #24. Делать последней — зависит от #24 (окно данных) и желательно от Objective integration (Objective_Integration_May07_2026 в graph) для точных registration_date per flat.

Часть пакета **recommend_mix v3**: см. #22 #23 #24. **Делать последней** — зависит от #24 (окно данных) и желательно от Objective integration (Objective_Integration_May07_2026 в graph) для точных registration_date per flat.
lekss361 commented 2026-05-11 19:24:17 +00:00 (Migrated from github.com)

Реализовано в commits 369b5a4 (view) + c31da62 (backend + frontend).

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

  • View v_bucket_success_score (migration 86): per-(district × class × bucket) агрегаты за 24 мес — avg_velocity (из domrf_kn_sale_graph.contracted), avg_price, avg_area, n_deals (>= 30). Z-scores нормированы по группе. success_score = velocity_z × 0.5 + price_z × 0.3 - area_z × 0.2.
  • _bucket_success_ranking в analytics_queries
  • В recommend_mix: top bucket по success_score получает +10% share, остальные пропорционально уменьшаются. Bucket помечается is_top_success: true.
  • scope: success_ranking: List[{bucket, success_score, n_deals, velocity_z, price_z, area_z}]

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

2-к 45-60: success_score=0.94, n_deals=64  ← top, boost +10%, is_top_success=true
1-к 30-45: success_score=0.05, n_deals=61
80+ м²:    success_score=-0.41, n_deals=86
3-к 60-80: success_score=-0.58, n_deals=65

Рекомендация смещена в пользу 2к 45-60 м² (share 32.1% вместо raw distribution).

Frontend:

  • RecommendBucketsTable: колонка "Успех" с для is_top_success
  • RecommendVelocityPanel: банер "💎 Рекомендация смещена в пользу 2-к 45-60 — лучшая динамика в районе (64 сделок, успех 0.94)"
Реализовано в commits 369b5a4 (view) + c31da62 (backend + frontend). **Что добавлено:** - View `v_bucket_success_score` (migration 86): per-(district × class × bucket) агрегаты за 24 мес — avg_velocity (из domrf_kn_sale_graph.contracted), avg_price, avg_area, n_deals (>= 30). Z-scores нормированы по группе. `success_score = velocity_z × 0.5 + price_z × 0.3 - area_z × 0.2`. - `_bucket_success_ranking` в analytics_queries - В `recommend_mix`: top bucket по success_score получает +10% share, остальные пропорционально уменьшаются. Bucket помечается `is_top_success: true`. - scope: `success_ranking: List[{bucket, success_score, n_deals, velocity_z, price_z, area_z}]` **Verification (Академический Comfort):** ``` 2-к 45-60: success_score=0.94, n_deals=64 ← top, boost +10%, is_top_success=true 1-к 30-45: success_score=0.05, n_deals=61 80+ м²: success_score=-0.41, n_deals=86 3-к 60-80: success_score=-0.58, n_deals=65 ``` Рекомендация смещена в пользу 2к 45-60 м² (share 32.1% вместо raw distribution). **Frontend:** - RecommendBucketsTable: колонка "Успех" с ⭐ для is_top_success - RecommendVelocityPanel: банер "💎 Рекомендация смещена в пользу 2-к 45-60 — лучшая динамика в районе (64 сделок, успех 0.94)"
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#25
No description provided.