Множители доверительного интервала по регионам #3540

Merged
lekss361 merged 1 commit from feat/pi-multipliers-by-region into main 2026-09-16 19:08:50 +00:00
Owner

Зачем

Вилка цены строилась множителями 0.649 / 1.392 — эмпирические p10/p90 отношения цены сделки к предсказанной, снятые один раз на Екатеринбурге (#1966). Заявлено 80% попаданий; фактически не выдерживается нигде, и хуже всего как раз в регионе калибровки.

Замер

16.09.2026, --engine full --sample 2000 --since 2025-06-01 --spread scattered --seed 42 --resolve-house-id --pi-report, гедоническая коррекция уже выключена (#3538).

регион n p10 p50 p90 покрытие текущей вилки
77 Москва 1969 0.448 1.043 1.440 71.2%
50 область 1632 0.703 1.117 1.500 74.8%
66 ЕКБ 1360 0.649 1.143 1.584 66.2%

Воспроизведено на независимой выборке (seed 777): 77 → 0.453/1.040/1.455, 50 → 0.701/1.115/1.514. Устойчиво до третьего знака.

Что это значит для продукта

Честная вилка по Москве заметно ШИРЕ нынешней: относительная ширина 0.96 против 0.72. Это осознанный размен — либо диапазон отражает реальный разброс, либо мы продолжаем обещать 80% и давать 71%. Здесь выбран первый вариант. Если продукт предпочтёт узкий диапазон, правильный ход — перестать называть его 80%-ным, а не оставлять числа как есть.

Отдельно видна дыра: московские студии (n=145) — покрытие 49.7%, p10 0.304. Разрез по комнатам харнесс печатает, но множители пока только региональные.

Реализация

  • pi_multipliers_for_region(region_code) — по образцу sber_region_series_name: карта, фолбэк на прежние скаляры, warning при промахе.
  • Регион берётся из того же target_region_code, которым уже резолвятся коэффициент asking→sold и ДКП-коридор. Второго источника не заведено.
  • Живой прогон харнесса тоже получает region_code — иначе замер молча считал бы старые скаляры и показывал покрытие, которого в проде нет. Замороженный реплей фикстуры региона не передаёт, его путь байт-в-байт прежний: регресс-гейт не двигается, базлайн не пересобирался.
  • Существующие тесты вилки хардкодили скаляр и стали бы зелёными по случайности (для 66 верхний множитель теперь 1.584, а не 1.392) — переведены на резолвер.

Что НЕ чинит этот PR

p50 > 1 во всех трёх регионах: точка по-прежнему занижена на 4-14%. Причина отдельная — коэффициент asking→sold усредняет дисконт за 12 месяцев, а дисконт сузился. Замер по возрасту сделок (Москва): сделки с 2026-03 → сдвиг −12.7%, с 2025-06 → −3.4%, с 2024-06 → +1.8%. Занижение растёт на свежих сделках, то есть это не недоучёт роста рынка, а устаревший дисконт. Правка отдельным PR — она двигает цены.

Test plan

  • pytest по 6 файлам вилки + регресс-гейт → 106 passed (проверено в main-сессии)
  • Регресс-гейт и roundtrip фикстуры зелёные без пересборки базлайна
  • ruff format + ruff check — чисто
  • После деплоя — контрольный --pi-report по трём регионам: achiev% должен подняться к 80
## Зачем Вилка цены строилась множителями `0.649` / `1.392` — эмпирические p10/p90 отношения цены сделки к предсказанной, снятые один раз на Екатеринбурге (#1966). Заявлено 80% попаданий; фактически не выдерживается нигде, и хуже всего как раз в регионе калибровки. ## Замер 16.09.2026, `--engine full --sample 2000 --since 2025-06-01 --spread scattered --seed 42 --resolve-house-id --pi-report`, гедоническая коррекция уже выключена (#3538). | регион | n | p10 | p50 | p90 | покрытие текущей вилки | |---|---|---|---|---|---| | 77 Москва | 1969 | 0.448 | 1.043 | 1.440 | 71.2% | | 50 область | 1632 | 0.703 | 1.117 | 1.500 | 74.8% | | 66 ЕКБ | 1360 | 0.649 | 1.143 | 1.584 | **66.2%** | Воспроизведено на независимой выборке (seed 777): 77 → 0.453/1.040/1.455, 50 → 0.701/1.115/1.514. Устойчиво до третьего знака. ## Что это значит для продукта Честная вилка по Москве заметно ШИРЕ нынешней: относительная ширина 0.96 против 0.72. Это осознанный размен — либо диапазон отражает реальный разброс, либо мы продолжаем обещать 80% и давать 71%. Здесь выбран первый вариант. Если продукт предпочтёт узкий диапазон, правильный ход — перестать называть его 80%-ным, а не оставлять числа как есть. Отдельно видна дыра: московские студии (n=145) — покрытие 49.7%, p10 0.304. Разрез по комнатам харнесс печатает, но множители пока только региональные. ## Реализация - `pi_multipliers_for_region(region_code)` — по образцу `sber_region_series_name`: карта, фолбэк на прежние скаляры, `warning` при промахе. - Регион берётся из того же `target_region_code`, которым уже резолвятся коэффициент asking→sold и ДКП-коридор. Второго источника не заведено. - **Живой прогон харнесса тоже получает `region_code`** — иначе замер молча считал бы старые скаляры и показывал покрытие, которого в проде нет. Замороженный реплей фикстуры региона не передаёт, его путь байт-в-байт прежний: регресс-гейт не двигается, базлайн не пересобирался. - Существующие тесты вилки хардкодили скаляр и стали бы зелёными по случайности (для 66 верхний множитель теперь 1.584, а не 1.392) — переведены на резолвер. ## Что НЕ чинит этот PR `p50 > 1` во всех трёх регионах: точка по-прежнему занижена на 4-14%. Причина отдельная — коэффициент asking→sold усредняет дисконт за 12 месяцев, а дисконт сузился. Замер по возрасту сделок (Москва): сделки с 2026-03 → сдвиг −12.7%, с 2025-06 → −3.4%, с 2024-06 → +1.8%. Занижение растёт на свежих сделках, то есть это не недоучёт роста рынка, а устаревший дисконт. Правка отдельным PR — она двигает цены. ## Test plan - [x] `pytest` по 6 файлам вилки + регресс-гейт → 106 passed (проверено в main-сессии) - [x] Регресс-гейт и roundtrip фикстуры зелёные без пересборки базлайна - [x] `ruff format` + `ruff check` — чисто - [ ] После деплоя — контрольный `--pi-report` по трём регионам: `achiev%` должен подняться к 80
lekss361 added 1 commit 2026-09-16 18:28:28 +00:00
feat(estimator): множители доверительного интервала по регионам
All checks were successful
CI Trade-In / changes (pull_request) Successful in 9s
CI / changes (pull_request) Successful in 12s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI Trade-In / backend-tests (pull_request) Successful in 4m50s
3280fa43ac
Вилка строилась множителями 0.649/1.392 — эмпирические p10/p90 отношения
цены сделки к предсказанной, снятые один раз на Екатеринбурге (#1966).
Заявлено 80% попаданий; фактически не выдерживается нигде, и хуже всего
как раз в регионе калибровки.

Замер 16.09.2026, --engine full --sample 2000 --since 2025-06-01 --spread
scattered --seed 42 --resolve-house-id --pi-report, гедоническая коррекция
уже выключена:

  регион   n      p10     p50     p90    покрытие текущей вилки
  77      1969    0.448   1.043   1.440   71.2%
  50      1632    0.703   1.117   1.500   74.8%
  66      1360    0.649   1.143   1.584   66.2%

Воспроизведено на независимой выборке (seed 777): 77 → 0.453/1.040/1.455,
50 → 0.701/1.115/1.514. Числа устойчивы до третьего знака.

Резолвер pi_multipliers_for_region сделан по образцу sber_region_series_name
(карта, фолбэк на скаляры, warning при промахе), регион берётся из того же
target_region_code, которым уже резолвятся коэффициент asking→sold и
ДКП-коридор — второго источника не заведено.

Живой прогон харнесса теперь тоже получает region_code: иначе замер молча
считал бы старые скаляры и показывал покрытие, которого в проде нет.
Замороженный реплей фикстуры региона не передаёт, его путь байт-в-байт
прежний — регресс-гейт не двигается, базлайн не пересобирался.

Существующие тесты вилки брали скаляр хардкодом и стали бы зелёными по
случайности (для 66 верхний множитель теперь 1.584, а не 1.392) — они
переведены на резолвер.

NB: p50 > 1 во всех трёх регионах, то есть точка по-прежнему занижена на
4-14%. Это ОТДЕЛЬНАЯ незакрытая задача — коэффициент asking→sold усредняет
дисконт за 12 месяцев, а дисконт сузился. Замер по возрасту сделок
(Москва): с 2026-03 сдвиг -12.7%, с 2025-06 -3.4%, с 2024-06 +1.8%.
lekss361 merged commit 1c039b358c into main 2026-09-16 19:08:50 +00:00
lekss361 deleted branch feat/pi-multipliers-by-region 2026-09-16 19:08:51 +00:00
Sign in to join this conversation.
No reviewers
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#3540
No description provided.