feat(tradein/estimator): штраф за неизвестный год/тип дома — флагом, default OFF (#2936) #3015
No reviewers
Labels
No labels
Fable 5 ревью
GG-форсайт
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
feedback/max
generative
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
ИРД
вторичка
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#3015
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "feat/2936-null-penalty-flag"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Флаг вместо правки формулы — и измеренный ответ на вопрос, который задача оставила открытым: «какой отбор точнее».
Что сделано
Флаг
estimate_unknown_attr_penalty_enabled, default OFF. Кандидат с NULLyear_built/house_typeполучает медианный по пулу штраф того же признака среди тех, у кого он известен — не наказание и не награда, по тем же термам, что SQL (abs(Δyear)/12.0,1.5за несовпадение). Лежит в Python-слое после SQL, рядом с kitchen/ceiling (#2012), по тому же контракту: включать — только по бэктесту.Без чего флаг был бы мёртв — и был в первой редакции.
_ANALOG_SELECT_COLSне выбиралyear_built/house_type: SQL считал по ним CASE, но в словарь кандидата колонки не попадали, Python-слой виделNoneу всех и не штрафовал никого по построению. Поймал probe-логом в прод-оверлее:pool=30 null_year=30. Добавлены в три места (константа, внешние SELECT тиров H/W, внутреннийbaseTier W — он строится явным списком). Контроль: флаг OFF с колонками и без — метрики бэктеста идентичны до сотых. На инвариант стоит тест по исходнику запросов.Живой A/B — бэктест в прод-контейнере
Оверлей
/tmp/ab(прод-код + этот diff),--city Екатеринбург --sample 300, одна и та же выборка в обоих прогонах (проверено поdeal_id: 300 общих).Почему эффект в разы меньше, чем замер в задаче (×0.20 avito)
Тот замер шёл по SQL тира H без стратификации и без квоты. В боевом пути — измерено по фикстурам A/B:
MIN_ANALOGS_PER_SOURCE=5, раздаётся ДО сортировки остатка; штраф по построению переставляет меньше половины слотов;Что это значит
Артефакт в формуле реален, флаг его корректно лечит (состав меняется, probe видит штрафы), но на итоговую цену он не влияет измеримо. Оснований включать по умолчанию нет — и это и есть ответ, ради которого флаг заводился вместо правки формулы.
Оговорки, которые я обязан назвать
ORDER BY id DESC), одна выборка, один город. Не «весь рынок».--city) берёт 300 последних по id с geom — это малые города Q2 2024 (Тагил, Каменск…), где пулы 6–9 и штрафу нечего переставлять. Первые два A/B я прогнал именно так и получил «0 различий» — это артефакт выборки, не результат.deal_id, перегнано.Как проверено
test_2936_unknown_attr_penalty.py— 7 тестов: медиана штрафа для NULL-года и NULL-типа, симметрия с SQL при неизвестном target, sparse-пропуск при< min_n, дефолт OFF, воспроизведение SQL-термов, и сторож «внешние SELECT тиров H/W выбирают year_built/house_type» (иначе флаг мёртв молча).listings, новые колонки её не трогают).-k "estimat or analog"— 735 passed.Часть #2936.