Перейти к содержимому
Ступень 1111.4 Расти дальше

Соревнования: Kaggle и другие

Как устроены соревнования по анализу данных — задача, метрика, публичный и приватный лидерборд, лимиты на посылки, — почему подгонка под публичную часть обманывает (симуляции перетряски и атаки Блюма–Хардта), как строить локальную валидацию, которой можно верить, вести соревнование от бейзлайна до ансамбля, играть в команде и честно показать результат в резюме. Плюс китайская платформа Тяньчи и соревнования с LLM.

УРОКstage-11/11-4-growth/03-competitions.mdx2 чУрок 3 из 5
После урока вы сможете
  • Объяснить устройство соревнования — метрика, публичный и приватный лидерборд, лимиты на посылки — и почему выбор по публичной части даёт оптимистичную оценку
  • Построить локальную валидацию по образцу теста, проверить её согласие с лидербордом и найти сдвиг между train и test состязательной валидацией
  • Вести соревнование по плану — сильный бейзлайн, итерации с журналом, ансамбль на out-of-fold предсказаниях, выбор финальных посылок — и читать решения победителей
  • Описать результат соревнования в резюме так, чтобы его можно было проверить

В уроке 2.4.4 вы честно оценивали модель: тест открывали один раз, все решения принимали по кросс-валидации. Соревнование по анализу данныхсоревнование по анализу данныхEN data science competitionЗадача, данные и метрика заданы организатором, участники присылают предсказания для теста без меток, места определяет скрытая часть теста. Площадки — Kaggle, Tianchi (Alibaba) и другие. — та же задача, только против вас тысячи участников, а ошибки в оценке стоят мест в таблице. Это быстрая внешняя проверка навыков: метрика одна для всех, данные одни для всех, и сразу видно, где вы.

Чему соревнования учат хорошо и чему не учат:

УчатНе учат
быстрые итерации: идея → эксперимент → число за часыставить задачу: что предсказывать и зачем (11.2.1)
дисциплину валидации — ошибка в ней наказывается сразувыбирать метрику: в соревновании она задана заранее
признаки, бустинг, дообучение моделей, ансамблисобирать и размечать данные (11.1.1)
читать чужие решения и находить в них главноеукладываться в задержку и бюджет (11.1.5)
работать в команде под дедлайнподдерживать модель месяцами и объяснять её заказчику

Две привычки из соревнований на работе вредят. Ансамбль из двадцати моделей ради +0.001 к метрике в продакшене никто не будет поддерживать. А утечку, которую в соревновании иногда можно законно использовать (в уроке 2.4.2 — утечки через ID и порядок строк), на работе нужно устранять: в момент прогноза её не будет.

flowchart LR
T["train: признаки + метки"] --> M["ваша модель<br/>и локальная валидация"]
X["test: только признаки"] --> M
M --> S["посылка: прогноз<br/>для каждой строки теста"]
S --> P["публичная часть теста<br/>балл виден сразу"]
S --> Q["приватная часть теста<br/>скрыта до конца"]
Q --> F["итоговые места"]
Участник видит только публичный балл; места решает приватная часть, на которой никто ничего не подбирал
ЭлементЧто этоНа что смотреть в правилах
Задача и данныеtrain с метками, test без метоккак разбиты train и test: случайно, по времени, по группам
Метрикаформула, по которой считают баллточная формула: под RMSE и MAE, под AUC и log-loss нужны разные приёмы (урок 2.2.3)
Публичный лидербордпубличный и приватный лидербордEN public / private leaderboardТест соревнования делят на две части. Публичная видна во время соревнования после каждой посылки, приватная открывается в конце и решает итоговые места. В китайских соревнованиях часто похожая схема с двумя тестовыми наборами: «рейтинг A» во время соревнования и «рейтинг B» в финале.балл на части теста, виден после каждой посылкикакая доля теста в публичной части — указана на странице лидерборда
Приватный лидербордбалл на остальной части, открывается в концеименно он решает места
Лимит посылоксколько посылок в деньлимит — защита от подгонки, о ней ниже
Финальный выборкакие посылки идут в зачётсколько посылок можно отметить финальными
Код-соревнованиепосылаете не файл, а ноутбук; он работает на скрытом тесте на железе площадкилимиты времени, GPU, доступа в интернет
Внешние данные и моделиможно ли брать чужие датасеты и предобученные весачасто разрешено, если источник открыт для всех участников; условия — в правилах

Во многих китайских соревнованиях встречается другая схема: два тестовых набора. Во время соревнования считается «таблица A» на тесте A, в финале выдают тест B, и места решает «таблица B». В учебном соревновании Datawhale × Тяньчи о ценах подержанных автомобилей из урока 2.4.2 данные так и разбиты: 150 тысяч строк train и по 50 тысяч в тестах A и B, метрика MAE.

Почему нельзя подгоняться под публичную часть

Заголовок раздела «Почему нельзя подгоняться под публичную часть»

Это урок 2.4.4 в новых декорациях: публичный лидерборд — та же валидация, на которой каждый день принимают решения. Значит, его оценка становится оптимистичной. Сколько в нём шума? При точности 0.8 и 3000 строк в публичной части стандартная ошибка балла 0.8⋅0.2/3000≈0.0073\sqrt{0.8 \cdot 0.2 / 3000} \approx 0.0073, то есть 95%-интервал — примерно ±1.4\pm 1.4 п.п. Две близкие посылки сравниваются точнее — парно, на одних и тех же строках (урок 1.3.4): значение имеют только строки, где их ответы расходятся. Если они расходятся на 4% строк (120 из 3000), шум разности — ±1.96⋅0.04/3000≈±0.7\pm 1.96 \cdot \sqrt{0.04 / 3000} \approx \pm 0.7 п.п. «Улучшение» на 0.3 п.п. после очередной посылки — всё ещё шум. Кросс-валидация на 20 000 строк train шумит в 2.6 раза меньше публичного балла: ±0.55\pm 0.55 п.п.

Возьмём участника с 50 вариантами модели, истинная точность которых от 0.800 до 0.810 — разница реальна, но мала. Для каждого варианта он видит две шумные оценки: CV на 20 000 строк и публичный балл на 3000 строк; места решает приватная часть на 7000 строк. Повторим соревнование 2000 раз (это функция selection_gap из задания ниже):

балл на публичном балл на приватном
выбор по публичному 0.8224 0.8072
выбор по CV — 0.8089

Вариант, выбранный по публичному лидерборду, обещает 0.822, а на приватной части даёт 0.807: завышение 1.5 п.п. Выбор по CV не только честнее, но и лучше — 0.809. Причина та же, что в уроке 2.4.4: из многих шумных оценок максимум выбирает того, кому повезло. Побеждает оценка по большей выборке. Если бы CV была на 500 строках, она шумела бы сильнее лидерборда, и выбор по ней проиграл бы — это тоже проверит задание.

Отсюда правило, которое на Kaggle формулируют коротко: доверяйте своей CV (trust your CV). Публичный балл — ещё одна оценка, причём по самой маленькой выборке.

Перетряска: что происходит с таблицей в последний день

Заголовок раздела «Перетряска: что происходит с таблицей в последний день»

Сымитируем целое соревнование: 300 команд почти равной силы, у каждой по 20 посылок, каждая выбирает лучшую по публичному лидерборду.

import numpy as np
rng = np.random.default_rng(0)
n_teams, n_subs = 300, 20 # 300 команд, у каждой по 20 посылок
n_public, n_private = 3000, 7000 # строк в публичной и приватной частях теста
skill = 0.80 + 0.004 * rng.standard_normal(n_teams) # истинная точность команд
# каждая посылка — то же умение плюс шум конечной выборки
pub = rng.binomial(n_public, skill[:, None], (n_teams, n_subs)) / n_public
priv = rng.binomial(n_private, skill[:, None], (n_teams, n_subs)) / n_private
best = pub.argmax(axis=1) # выбор посылки по публичному лидерборду
rows = np.arange(n_teams)
pub_score, priv_score = pub[rows, best], priv[rows, best]
pub_rank = (-pub_score).argsort().argsort() + 1 # место 1 — лучший
priv_rank = (-priv_score).argsort().argsort() + 1
top10_pub = set(np.where(pub_rank <= 10)[0])
top10_priv = set(np.where(priv_rank <= 10)[0])
print(f"средний публичный балл топ-10: {pub_score[pub_rank <= 10].mean():.4f}")
print(f"их же приватный балл: {priv_score[pub_rank <= 10].mean():.4f}")
print(f"остались в топ-10 приватного: {len(top10_pub & top10_priv)} из 10")
moved = np.abs(pub_rank - priv_rank)[pub_rank <= 50]
print(f"топ-50 публичного: медианный сдвиг {np.median(moved):.0f} мест, максимум {moved.max()}")
средний публичный балл топ-10: 0.8240
их же приватный балл: 0.8064
остались в топ-10 приватного: 2 из 10
топ-50 публичного: медианный сдвиг 40 мест, максимум 233

Из публичной десятки в приватной остались двое, а у участников из публичного топ-50 медианный сдвиг — 40 мест. Это перетряска (shake-up). Она тем сильнее, чем меньше публичная часть, чем ближе команды по силе и чем больше посылок выбирали по лидерборду. Допущение симуляции — все команды почти равны (разброс умения 0.4 п.п.); в реальном соревновании сильные команды отрываются, и перетряска скромнее, но устроена так же.

Крайний случай: «обучиться» на лидерборде, не глядя в данные

Заголовок раздела «Крайний случай: «обучиться» на лидерборде, не глядя в данные»

Аврим Блюм и Мориц Хардт в статье о лидербордах (arXiv:1502.04585, ICML 2015) описали атаку, которая показывает предел этой проблемы. Задача бинарная, метки скрыты. Атакующий:

  1. отправляет kk случайных посылок из нулей и единиц;
  2. оставляет те, у которых публичная точность не ниже 0.5 (им случайно повезло на публичных строках);
  3. голосует ими большинством по каждой строке.

Каждая оставленная посылка чуть-чуть совпадает с публичными метками сильнее случайного, и голосование складывает эти крохи. По теореме из статьи публичная ошибка падает ниже 0.5 на величину порядка k/n\sqrt{k/n}, где nn — размер публичной части. На приватной части посылки остаются случайными — точность 0.5. В нашем задании при 2000 публичных строках и 400 посылках атака даёт 0.600 на публичной части и 0.491 на приватной: модель, не видевшая ни одного признака, поднимается в таблице на 10 пунктов.

Поэтому площадки ограничивают число посылок в день и решают места по приватной части. Блюм и Хардт предложили и защиту — механизм Ladder («лестница»): публиковать новый балл, только если он лучше уже опубликованного больше чем на шаг η\eta, а иначе показывать старый лучший. Старый балл ничего не говорит о новой посылке, и та же атака против лестницы даёт в задании 0.508 — почти ничего. Ответственный участник делает то же самое сам: не меняет решение из-за разницы, которая меньше шума.

Локальная валидация, которой можно верить

Заголовок раздела «Локальная валидация, которой можно верить»

Хорошая CV повторяет то, как организатор отделил test от train. Это главный вопрос из урока 2.4.4: как модель будут применять?

  • test — более поздний период → обучение на прошлом, валидация на последнем отрезке (TimeSeriesSplit или один временной разрез);
  • в test новые пользователи, магазины, пациенты → GroupKFold по их id;
  • классы несбалансированы → StratifiedKFold;
  • фолды фиксируются один раз (файл с номером фолда для каждой строки) и одинаковы для всех моделей и всех членов команды — иначе сравнения и ансамбли будут нечестными.

Проверка согласия CV и лидерборда. Записывайте в журнал каждую посылку: CV, публичный балл, что изменили (урок 11.1.3). Если CV растёт, а публичный балл стоит на месте или падает — либо шум (сравните разницу с шумом парного сравнения из раздела выше), либо CV устроена не как тест.

Состязательная валидациясостязательная валидацияEN adversarial validationПроверка сдвига между train и test: склеить их, поставить метку «строка из теста?» и обучить классификатор. ROC-AUC около 0.5 — выборки неразличимы и локальной валидации можно верить; AUC около 1 — есть признак, который выдаёт тест (часто время), и валидацию нужно строить иначе. отвечает на вопрос «похож ли test на train». Склеиваем их, ставим новую метку «строка из теста?» и учим классификатор с кросс-валидацией. Если он не может отличить, ROC-AUC около 0.5, и случайная CV честна. Пример на синтетике: train — объявления за год, test — следующий квартал, цены в тесте выше на 15%.

import numpy as np
from sklearn.ensemble import HistGradientBoostingClassifier
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import cross_val_predict
rng = np.random.default_rng(0)
n = 3000
# столбцы: день публикации, цена, число комнат, шум
X_tr = np.column_stack([rng.integers(0, 365, n), rng.lognormal(10, 0.5, n),
rng.integers(1, 6, n), rng.normal(0, 1, n)])
X_te = np.column_stack([rng.integers(365, 455, n), rng.lognormal(10, 0.5, n) * 1.15,
rng.integers(1, 6, n), rng.normal(0, 1, n)])
def adversarial_auc(cols):
X = np.vstack([X_tr[:, cols], X_te[:, cols]])
is_test = np.r_[np.zeros(n), np.ones(n)] # новая цель: «строка из теста?»
clf = HistGradientBoostingClassifier(max_iter=100, random_state=0)
p = cross_val_predict(clf, X, is_test, cv=5, method="predict_proba")[:, 1]
return roc_auc_score(is_test, p)
print(f"все признаки: AUC = {adversarial_auc([0, 1, 2, 3]):.3f}")
print(f"без day: AUC = {adversarial_auc([1, 2, 3]):.3f}")
print(f"без day и price: AUC = {adversarial_auc([2, 3]):.3f}")
все признаки: AUC = 1.000
без day: AUC = 0.553
без day и price: AUC = 0.501

AUC 1.000 говорит: test отделён по времени, день публикации выдаёт его полностью. Значит, CV должна быть временной, а сам день — не признаком, а осью разбиения. Без дня остаётся слабый сдвиг цен (0.553): модель, обученная на старых ценах, будет немного ошибаться на новых, и полезно проверить признаки, не зависящие от инфляции (цена относительно средней по району и месяцу). Счёт занимает несколько секунд на одном ядре.

flowchart TD
A["Условие, метрика, правила<br/>первая посылка в первый день"] --> B["Разведка данных<br/>как устроен test (урок 2.4.2)"]
B --> C["Валидация по образцу test<br/>фолды зафиксированы"]
C --> D["Сильный бейзлайн<br/>LightGBM или предобученная модель"]
D --> E{"Идея"}
E --> F["Эксперимент: одно изменение<br/>запись в журнал: CV и посылка"]
F -->|"CV выросла больше шума"| E
F -->|"нет"| E
E -->|"последняя неделя"| G["Ансамбль на OOF-предсказаниях"]
G --> H["Финальные посылки<br/>лучшая по CV + надёжная"]
Соревнование — цикл экспериментов вокруг валидации, которой вы доверяете

Первая посылка — в первый день. Константа или простейшая модель: проверить формат файла и увидеть, как публичный балл соотносится с CV. Ошибка формата за час до дедлайна стоит дороже любой модели.

Сильный бейзлайн. Для таблиц — градиентный бустингградиентный бустингEN gradient boosting (GBDT)Реализации — XGBoost, LightGBM, CatBoost. с параметрами по умолчанию и ранней остановкой (урок 2.4.3). Для текста и изображений — дообучение предобученной модели. Это точка отсчёта: каждое следующее изменение сравнивается с ней, а не с вашими надеждами.

Итерации. Одно изменение — один эксперимент, как в абляциях урока 11.4.1. На таблицах больше всего дают признакиконструирование признаков (feature engineering)EN feature engineeringПревращение сырых столбцов в признаки для модели: масштабирование, логарифм, кодирование категорий, признаки из дат и текста. из понимания данных — агрегаты по пользователю и времени, out-of-fold кодирование средним целевой переменнойкодирование средним целевой переменной (target encoding)EN target encodingКатегория → среднее цели по ней. Без out-of-fold и сглаживания протекает целевой переменной: у редких категорий кодировка почти равна метке., — и меньше всего тонкий подбор гиперпараметров. Каждое «улучшение» сравнивайте с шумом CV: разброс по фолдам и seed (урок 1.3.4).

Ансамбли. Почему усреднение помогает, вы видели в уроке 2.3.1: разброс среднего двух моделей с одинаковым разбросом σ2\sigma^2 и корреляцией ошибок ρ\rho равен σ2(1+ρ)/2\sigma^2 (1 + \rho) / 2. При ρ=0.9\rho = 0.9 (две похожие модели бустинга) это 0.95σ20.95 \sigma^2 — выигрыш 5%. При ρ=0.5\rho = 0.5 (например, бустинг и нейросеть на разных признаках) — 0.75σ20.75 \sigma^2. Поэтому в ансамбль берут разные модели, а не десять бустингов с разными seed. Веса смеси подбирают на out-of-fold (OOF) предсказаниях: для каждой строки train прогноз делает модель, обученная на остальных фолдах. Так веса учатся на честных прогнозах, а не на переобученных. Следующий шаг — стекинг: модель второго уровня (часто логистическая регрессия) учится на OOF-предсказаниях моделей первого уровня. Обе техники требуют одних и тех же фолдов у всех моделей.

Финальные посылки. Если можно отметить две, частая стратегия — лучшая по CV и «надёжная» (ансамбль попроще с хорошим согласием CV и лидерборда). Лучшая по публичному баллу — только если она же лучшая по CV.

После конца соревнования сильные команды часто публикуют разбор решения (writeup) в обсуждениях. Это концентрат опыта, но читать его надо как статью из урока 9.2.2:

  1. Валидация. Как они строили CV и насколько она совпадала с лидербордом? Это обычно самое переносимое.
  2. Что дало больше всего. Многие пишут прирост по шагам; часто одна-две идеи дают основную часть, остальное — доли.
  3. Что не сработало. Самая недооценённая часть: экономит вам недели.
  4. Повторить одну идею. Возьмите завершённое соревнование, воспроизведите главную идею на своей CV и отправьте посылку после дедлайна (для многих завершённых соревнований Kaggle принимает их и показывает оба балла). Это воспроизведение из урока 11.4.1, только с готовым лидербордом.

Объединяться выгодно, когда у каждого уже есть своя сильная и непохожая модель: тогда ансамбль даёт реальный прирост. Правила задают предельный размер команды и срок, после которого объединяться нельзя. Договоритесь в первый день: общий файл фолдов, общий формат OOF-предсказаний, общий журнал экспериментов, кто за что отвечает. Правила обычно запрещают приватно делиться кодом и данными с теми, кто не в вашей команде: публично — в ноутбуках и обсуждениях, доступных всем, — можно.

С ростом LLM появились соревнования, где модель — уже не бустинг на таблице. Типичные постановки (на Kaggle и других площадках):

Тип задачиЧто нужно уметьГде в курсе
решение математических или логических задач открытой моделью при ограничении на время и GPUинференс с ограничениями, квантизация, выбор и проверка ответа из нескольких7.1, 7.2, 6.4
предсказать, какой из двух ответов предпочтёт человекмодель предпочтений, как reward model6.3.2
отличить текст человека от сгенерированногоклассификатор на текстах, устойчивость к сдвигу4.3, 2.4
ответы на вопросы по документампоиск и RAG, оценка ответов8.2
дообучить небольшую модель под задачуSFT и LoRA при ограниченном бюджете6.2
агенты в игровой или симулированной средецикл агента, инструменты, RL8.3

Валидация здесь ещё сложнее: размеченных примеров для проверки часто мало, ответы длинные, LLM-судья шумит (урок 7.3.2), а открытые данные могли попасть в предобучение модели (загрязнение, урок 7.3.1). Правило то же: локальная оценка, которой вы доверяете, и скептическое отношение к публичной таблице.

ФорматДлительностьЧто решаетДля чего хорош
Соревнование (Kaggle, Тяньчи и другие)недели и месяцыметрика на приватной части теставалидация, моделирование, ансамбли
Учебное соревнование в курсенеделя–двепороги бейзлайновпервая практика без давления
ХакатонхакатонEN hackathonКороткое (обычно от суток до нескольких дней) соревнование команд, которые собирают работающий прототип; победителей выбирает жюри по демонстрации и защите, а не только по метрике.от суток до нескольких днейжюри: работающий прототип, демонстрация, защитапродукт целиком, командная работа, презентация

Учебные соревнования. На Kaggle для новичков есть бессрочные соревнования категории Getting Started (классика — Titanic и House Prices, на котором построен раздел 4.10 d2l-zh) и регулярные соревнования категории Playground. В открытом курсе ODS mlcourse.ai часть бонусных заданий — учебные соревнования Kaggle Inclass, где нужно побить бейзлайн; статьи курса есть на Хабре по-русски. В архиве курса машинного обучения ФКН ВШЭ (репозиторий ml-course-hse) среди домашних заданий есть отдельный раздел соревнований.

Русскоязычные хакатоны и соревнования проводят компании, вузы и сообщества; анонсы ищите в сообществе Open Data Science (ods.ai), на Хабре и на сайтах организаторов. Формат и правила у каждого свои: прежде чем тратить выходные, проверьте, кто владеет решением после конкурса (иногда права переходят организатору), как устроена оценка и можно ли публиковать код.

Хороший пункт в резюме проверяется за минуту и говорит, что умеете вы:

Kaggle, «[название соревнования]», 2026 — 87-е место из 1 450 команд по приватному лидерборду, в команде из трёх, моя часть — валидация и признаки. Временная CV с согласием с лидербордом ±0.002; признаки из журнала событий дали +0.012 AUC из итоговых +0.018. Код и разбор решения: github.com/…

Числа в примере условные — у вас будут свои. Что делает пункт сильным: место по приватному лидерборду и размер поля, ваша роль в команде, что именно сработало и насколько, ссылка на код и разбор. Слабый вариант — «топ-5% публичного лидерборда» или «accuracy 0.9871» без контекста: первое ничего не значит, второе непонятно без бейзлайна. На Kaggle есть система званий — от Novice до Grandmaster — отдельно за соревнования, ноутбуки, датасеты и обсуждения, и медали; работодатели в ML их узнают, но разбор решения и код говорят больше. Как вписать это в резюме и рассказать на собеседовании — в уроке 11.3.6.

Задание в браузере: публичный лидерборд, атака и «лестница»

Заголовок раздела «Задание в браузере: публичный лидерборд, атака и «лестница»»

Соберите четыре функции и проверьте на числах всё, о чём шла речь: точность на публичной и приватной частях, симуляцию «выбор по лидерборду против выбора по CV», атаку Блюма–Хардта и один шаг механизма Ladder. Тесты запускают атаку дважды: против обычного лидерборда и против «лестницы».

Публичный лидерборд: подгонка, атака и «лестница»numpy · нужен интернет6 тестов
"""Публичный лидерборд: выбор по нему, атака Блюма–Хардта и «Лестница» (Ladder)."""
import numpy as np


def split_accuracy(pred, y, public_mask):
    """Точность посылки на публичной и приватной частях теста.

    pred, y — массивы из 0 и 1 длины n; public_mask — массив bool длины n
    (True — строка входит в публичную часть). Вернуть (public_acc, private_acc) обычными float.
    """
    # TODO
    ...


def selection_gap(true_acc, n_cv, n_public, n_private, n_trials=2000, seed=0):
    """Монте-Карло: что даёт выбор финальной посылки по публичному лидерборду и по локальной CV.

    У участника k = len(true_acc) вариантов модели с истинными точностями true_acc. В каждом из n_trials
    повторов наблюдаем три шумные оценки каждого варианта (массивы формы (n_trials, k), в этом порядке):
      cv      = Binomial(n_cv, acc) / n_cv
      public  = Binomial(n_public, acc) / n_public
      private = Binomial(n_private, acc) / n_private
    Выбор по публичному — argmax(public) в каждой строке, выбор по CV — argmax(cv).
    Вернуть словарь средних по повторам (обычные float):
      'public_pick_public'  — публичный балл варианта, выбранного по публичному лидерборду;
      'public_pick_private' — приватный балл того же варианта;
      'cv_pick_private'     — приватный балл варианта, выбранного по CV;
      'optimism'            — public_pick_public − public_pick_private.
    """
    rng = np.random.default_rng(seed)
    # TODO
    ...


def boosting_attack(leaderboard, n_rows, k, seed=0):
    """Атака Блюма и Хардта (2015): поднять публичный балл, не глядя в данные.

    1) k случайных посылок из 0 и 1 длины n_rows (rng = np.random.default_rng(seed));
    2) по каждой ровно один раз спросить leaderboard(u) — публичную точность, по порядку;
    3) оставить посылки с точностью ≥ 0.5;
    4) вернуть их поэлементное большинство: 1, где среднее строго больше 0.5, иначе 0 (np.ndarray из int).
    """
    # TODO
    ...


def ladder_step(best, score, eta):
    """Один шаг «Лестницы» (Ladder) для точности (больше — лучше).

    best — уже опубликованное значение (None, если посылок ещё не было), score — точность новой посылки.
    Если best is None или score > best + eta, опубликовать score, округлённый до сетки шага eta:
    round(score / eta) * eta. Иначе снова опубликовать best. Вернуть опубликованное значение (float).
    """
    # TODO
    ...


if __name__ == "__main__":
    true = np.linspace(0.80, 0.81, 50)
    r = selection_gap(true, n_cv=20_000, n_public=3_000, n_private=7_000)
    print(r)
  1. Выберите учебное соревнование (Titanic, House Prices или учебное соревнование Тяньчи) и прочитайте правила: метрика, как разбит test, лимит посылок.
  2. В первый вечер — посылка-константа и бейзлайн LightGBM. Запишите CV и публичный балл в журнал.
  3. Постройте CV по образцу test и проверьте состязательной валидацией, похож ли test на train.
  4. Десять экспериментов по одному изменению; каждый — строка журнала «что изменил, CV ± разброс, публичный балл».
  5. Ансамбль из двух непохожих моделей на OOF-предсказаниях. Выберите финальную посылку по CV и после конца соревнования сравните с приватным баллом: насколько ваша CV оказалась честной?
  6. Прочитайте два разбора победителей и повторите одну их идею на своей CV.
Проверь себя6 вопросов
1 В публичной части 3000 строк, точность ваших посылок около 0.8. Новая посылка дала +0.3 п.п. на публичном лидерборде, CV не изменилась. Что разумнее всего?
2 Какие действия делают публичный балл оптимистичной оценкой? Выберите все верные.Можно выбрать несколько ответов
3 Атака Блюма–Хардта: при публичной части n=2000n = 2000 и k=400k = 400 случайных посылках публичная точность поднялась до 0.60. Что будет на приватной части?
4 Состязательная валидация дала ROC-AUC 0.99, и почти весь вклад — у признака «дата заявки». Что делать?
5 Две модели с одинаковым разбросом ошибок σ2\sigma^2 и корреляцией ошибок ρ=0.6\rho = 0.6. Во сколько раз разброс их среднего меньше разброса одной модели? Ответ — доля σ2\sigma^2, округлите до двух знаков.
6 Какой пункт резюме сильнее?
  • Соревнование — задача, метрика и тест без меток. Публичная часть теста видна всем и потому становится валидацией; места решает приватная часть (или тест B в китайских соревнованиях).
  • Выбор по публичному лидерборду оптимистичен: в симуляции завышение около 1.5 п.п., перетряска выбивает из топ-10 восьмерых, а атака Блюма–Хардта поднимает публичный балл на 10 пунктов без единого признака. Доверяйте CV.
  • Валидация повторяет разбиение train/test; состязательная валидация проверяет, похожи ли они. Фолды фиксированы и общие для всех моделей.
  • Стратегия: посылка в первый день → сильный бейзлайн → одно изменение за раз с журналом → ансамбль непохожих моделей на OOF-предсказаниях → финальный выбор по CV. Разборы победителей — читать и воспроизводить.
  • В резюме — место по приватному лидерборду, размер поля, ваша роль и ссылка на код.

Дальше: «Обратная связь: ментор, ИИ-ревьюер и сообщество» — где брать ревью своей работы, когда учитесь сами: ИИ-ментор курса, сообщества (в том числе Kaggle и ODS) и живые люди.