fix(mera/estimate): перефит хедоники поверх area-бакетного ratio — крупное жильё занижалось на 21% #3255

Merged
lekss361 merged 1 commit from fix/3248-hedonic-refit into main 2026-08-29 20:19:27 +00:00

1 commit

Author SHA1 Message Date
bot-backend
49907aba46 fix(mera/estimate): перефит хедоники поверх area-бакетного ratio — крупное жильё занижалось на 21%
All checks were successful
CI Trade-In / changes (pull_request) Successful in 8s
CI / changes (pull_request) Successful in 10s
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 4m55s
Коэффициенты хедоники зафичены 27.06.2026 (#2002), когда asking->sold ratio
ключевался ПО КОМНАТАМ. 05.08.2026 (#2620) ratio переключили на area-бакеты, то
есть под хедонику подставили другую базу, а её саму не пересчитали. Хедоника по
определению чинит остаток log(actual_sold / expected_sold) и верна только для
той базы, на которой фитилась. Итог: площадь штрафовалась дважды, bias по 4+
комнатам -21.4%. В выкупе занижение — это потерянные сделки.

Перефит на свежей прод-фикстуре (1269 оценённых сделок ЕКБ). larea выставлен в
0.0 НАМЕРЕННО: после #2620 площадь несёт area-бакетный ratio, а его форма —
перевёрнутая U (факт sold/ask по бакетам 0.786 / 0.829 / 0.899 / 0.954 / 0.864),
которую монотонный ln(area) выразить не может в принципе. Член стал избыточным и
тянул крупное жильё вниз ровно там, где рынок его не дисконтирует.

Результат на фикстуре:

  было   MAPE 13.90  bias -0.78 | студия +7.6  1к -0.5  2к -2.8  3к -5.3  4+ -21.4
  стало  MAPE 14.28  bias -1.61 | студия -3.1  1к -2.3  2к -0.4  3к -1.9  4+ -10.4

Худший перекос вдвое меньше, все прочие классы в пределах +-3.1%, покрытие
диапазона 86.13% -> 87.00%. Цена — +0.38 п.п. общего MAPE: хедоника сжимает
разброс за счёт года, и ослабление площадного члена этот эффект чуть уменьшает.

Критерии приёмки из #3248 выполнены частично: «все классы в пределах 12%» — да;
«4+ не хуже 8%» и «MAPE не хуже 14.17» — нет. Остаток -10.4% конфигом не
закрывается: ratio бакета 4 равен 0.8211 при фактических sold/ask 0.8640, то есть
занижен на ~5% ещё до всякой хедоники. Это пересчёт самой таблицы
(app/tasks/asking_to_sold_ratio.py) — отдельной задачей.

Три теста в test_estimator_hedonic.py развязаны от подгоняемых чисел: два
проверяют механизм клэмпов и теперь задают коэффициенты явно через monkeypatch,
третий сверяет наземную скидку с настройкой, а не с зашитым 0.8827. Иначе каждый
следующий перефит ломал бы тесты, которые про механизм, а не про подгонку.
2026-08-29 23:13:13 +03:00