Машинне навчання · Блок 1 · Тема 03

Три конверти

Навчальна, валідаційна і тестова вибірки. Найдешевша процедура в машинному навчанні — і та, помилка в якій коштує найдорожче.

Уяви студента, який готується до іспиту за збіркою задач із відповідями. Він розвʼязав усі сто задач, звірив кожну з відповіддю, вивчив розвʼязки напамʼять і тепер розвʼязує ці сто задач на 100%. Питання: що це число каже про його оцінку на іспиті? Абсолютно нічого. Бо на іспиті будуть інші задачі.

Модель у машинному навчанні — той самий студент. Вона теж бачила відповіді, теж може вивчити їх напамʼять, і теж покаже блискучий результат на тому, що вже бачила. Уся дисципліна чесного вимірювання якості зводиться до однієї ідеї: щоб дізнатись, чи навчилась модель, треба перевірити її на задачах, яких вона не бачила. Далі — як саме це робиться, чому вибірок потрібно три, а не дві, і які помилки непомітно перетворюють усю перевірку на самообман.

01 / МотиваціяНавчальна помилка завжди бреше

Почнемо з демонстрації, а не з теорії. Візьмемо просту модель — метод k найближчих сусідів. Він не має жодних формул: щоб класифікувати новий обʼєкт, модель шукає k найсхожіших обʼєктів серед тих, які їй показали, і повертає відповідь більшості з них.

Параметр k керує гнучкістю. При k = 1 модель відповідає за єдиним найближчим сусідом — і на навчальних даних це означає, що вона просто знаходить сама себе. Точність на навчальній вибірці буде рівно 100%, завжди, на будь-яких даних, навіть на чистому шумі. Це не досягнення, це визначення.

Інтерактив 1 · Чому не можна вірити точності на навчальних даних

Ліворуч — межа рішень методу k сусідів. Праворуч — дві криві точності залежно від k.

точність train
точність test
Що читати: при k = 1 навчальна точність рівно 100% — модель знаходить кожну точку саму в собі. Тестова при цьому найгірша: межа рішень порізана на клапті, які повторюють шум. Зі зростанням k межа згладжується, навчальна точність падає, а тестова спершу росте.

Різниця між двома кривими — це і є ціна самообману. Навчальна точність вимірює запамʼятовування. Тестова вимірює узагальнення — здатність працювати на нових даних. Нас цікавить винятково друга, і отримати її можна лише одним способом: відкласти частину даних убік і не давати моделі їх бачити.

02 / РозбиттяТри конверти, три ролі

Стандартна практика — розділити наявні дані на три незалежні частини. Слово «незалежні» тут ключове: жоден обʼєкт не має потрапити у дві частини одночасно.

вибіркахто її бачитьдля чого потрібнаяк часто торкаємось
trainалгоритм навчанняпідбір параметрів моделі: ваг, порогів, розбиттів дереващоразу під час навчання
validationти, дослідниквибір між моделями і гіперпараметрами: яке k, який степінь, яка архітектурадесятки й сотні разів
testніхто до самого кінцяодна незміщена оцінка якості моделі, яку ти вже обраврівно один раз

Формально різниця між train і validation у тому, хто підганяється під дані. На навчальній вибірці підганяється алгоритм: він крутить ваги, поки помилка не перестане падати. На валідаційній підганяєшся ти: дивишся на число, змінюєш гіперпараметр, запускаєш ще раз. Це той самий процес оптимізації — просто цикл проходить через людину. І він так само здатен перенавчитись.

Термінологія плутана. У частині літератури (і в бібліотеці scikit-learn) «validation» і «test» називають навпаки або зливають в одне. Не сперечайся про слова — важлива лише роль: одна відкладена вибірка потрібна для вибору, друга для звіту. І це мають бути різні вибірки.

03 / Прокляття переможцяЧому двох вибірок замало

Найпоширеніше заперечення звучить так: «навіщо три? Навчив на train, поміряв на test, обрав найкращу модель — хіба цього мало?» Мало. І щоб зрозуміти чому, треба побачити ефект, який в економіці називають прокляттям переможця (winner's curse).

Уяви, що ти виміряв точність двадцяти однаково хороших моделей на вибірці зі ста обʼєктів. Справжня точність кожної — рівно 80%, але виміряна коливається: комусь пощастило на кілька легких прикладів і вийшло 85%, комусь не пощастило і вийшло 74%. Тепер ти обираєш ту, що показала найбільше число, і звітуєш про 85%.

Проблема в тому, що ця модель виграла не тому, що вона краща, а тому, що їй більше пощастило на цій конкретній вибірці. Максимум із двадцяти шумних вимірювань систематично більший за справжнє значення. Ти обрав не найкращу модель — ти обрав найвдалішу похибку вимірювання.

E[ maxm точність̂m ]  >  maxm E[ точність̂m ]

Ця нерівність — вся суть у двох рядках. Математичне сподівання максимуму більше за максимум сподівань, і різниця тим більша, чим більше моделей ти порівнюєш і чим менша вибірка. Покрути обидва повзунки й подивись, як росте розрив:

Інтерактив 2 · Що станеться, якщо обирати модель по тесту

Кожна сіра точка — модель-кандидат. По горизонталі її справжня якість, по вертикалі — виміряна на тестовій вибірці.

вибір по тесту
насправді
вибір по валід.
насправді
Що видно: рожева точка — переможець за тестовою оцінкою. Вона майже завжди лежить вище лінії «оцінка = правда»: її обрали саме за те, що вимірювання їй підіграло. Бірюзова точка — модель, обрана по валідації; її оцінка на тесті чесна, бо тест не брав участі у виборі.

Звідси й потреба у третій вибірці. Валідаційна вибірка бере на себе увесь бруд: її оцінка після сотні експериментів справді стає завищеною, і це нормально — ми і не збиралися їй вірити. Її робота інша: ранжувати моделі між собою. А тестова лишається недоторканою, тому її число можна показувати людям.

04 / ДисциплінаТесту торкаємось рівно один раз

Правило звучить майже релігійно, але має цілком технічне обґрунтування. Кожен погляд на тестову вибірку — це біт інформації, який просочується у твої рішення. Побачив, що модель дала 82%, вирішив «спробую ще один варіант ознак» — і ти вже оптимізуєш під тест. Формально ти нічого не робив із даними, але процес вибору тепер залежить від них.

На практиці це дає таку послідовність:

  1. Розділив дані на три частини до того, як почав щось робити.
  2. Тестову частину поклав окремо і не відкривав.
  3. Навчав десятки моделей на train, порівнював їх на validation.
  4. Обрав переможця, зафіксував усі гіперпараметри, більше нічого не змінюєш.
  5. Тепер, і тільки тепер, порахував метрику на test. Це число — у звіт.
Що робити, якщо результат не сподобався. Чесна відповідь: або приймати його, або визнати, що ти починаєш новий цикл — і тоді потрібна нова тестова вибірка, до якої ти ще не торкався. Саме тому в змаганнях Kaggle існує «прихована» частина тесту, а серйозні лабораторії тримають фінальний набір під замком у людини, яка не бере участі в розробці.

05 / ВитікЩо таке витік даних

Витік даних (data leakage) — це ситуація, коли інформація з тестової вибірки якимось шляхом дісталася до моделі під час навчання. Оцінка після цього стає завищеною, іноді до абсурду: 99% на тесті і повний провал у продакшені.

Найнеприємніша властивість витоку — він не виглядає як помилка. Код працює, метрика чудова, тести проходять. Єдиний симптом — «підозріло добре». Тому головна навичка тут не діагностична, а профілактична: знати чотири типові сценарії й перевіряти їх щоразу.

06 / СценаріїЧотири способи отруїти собі оцінку

Сценарій 1 · Препроцесинг до розбиття

Класика. Ти завантажив дані, нормалізував ознаки, заповнив пропуски середнім, відібрав найкорисніші ознаки — і лише потім розділив на train і test. Здається невинним: жодних міток, самі числа. Але кожна з цих операцій рахувалась по всіх даних, включно з тестовими. Середнє, яким ти заповнив пропуски, знає про тестові обʼєкти. Ознаки, які ти відібрав, відібрані з урахуванням тестових міток.

Правило: будь-яке перетворення, що має параметри (середнє, стандартне відхилення, мінімум, максимум, список обраних ознак, словник токенів), налаштовується на train і лише застосовується до val і test. У scikit-learn це буквально різниця між fit_transform на навчальній частині і transform на решті — і саме тому існує Pipeline.

Сценарій 2 · Дублікати й групи

Один пацієнт зробив три знімки. Один користувач залишив пʼятдесят відгуків. Один товар зʼявляється в каталозі під двома артикулами. Якщо розбивати випадково по рядках, копії того самого обʼєкта опиняться і в train, і в test — і модель просто впізнає їх, а не узагальнює.

Лікується груповим розбиттям: спочатку ділиш групи (пацієнтів, користувачів, товари), потім усі рядки групи їдуть в одну вибірку цілком.

Сценарій 3 · Витік із майбутнього

Якщо дані мають час, випадкове розбиття вбиває задачу. Модель, навчена на подіях за весь рік, передбачає події березня, «знаючи» вересень. У житті такої розкоші не буде: завтрашній день прогнозують, маючи лише вчорашній. Розбиття для часових рядів завжди хронологічне: минуле у train, майбутнє у test.

Сценарій 4 · Ознака, що містить відповідь

Найковарніший випадок. У таблиці є колонка, яка потрапила туди після того, як відповідь стала відома. Прогнозуєш відтік клієнтів — а серед ознак є «дата закриття рахунку». Прогнозуєш дефолт — а є «сума списаного боргу». Модель знаходить цю ознаку миттєво і дає майже ідеальну якість.

Симптом: одна ознака дає підозріло високу якість сама по собі. Лікування: для кожної ознаки поставити питання «чи буде вона відома на момент прогнозу?» — і безжально викидати ті, для яких відповідь «ні».

Інтерактив нижче міряє реальний масштаб трьох із цих сценаріїв. Порівняй, наскільки різні за силою витоки бувають:

Інтерактив 3 · Скільки коштує кожен вид витоку

Дві гістограми: рожева — оцінка з витоком, бірюзова — чесна. Пунктир — справжня якість моделі.

з витоком
чесно
завищення оцінки
Головне спостереження: витоки різні за силою. Нормалізація по всіх даних дає невелике, але систематичне зміщення, яке тане зі зростанням вибірки. Відбір ознак і дублікати ламають оцінку повністю: там завищення вимірюється десятками відсоткових пунктів, і навіть на великій вибірці лишається двозначним.

07 / БалансСтратифікація

Випадкове розбиття справедливе в середньому, але кожне конкретне розбиття — це випадкова величина. Якщо класи збалансовані, все гаразд. Якщо мінорний клас складає 2% — а це типово для шахрайства, рідкісних хвороб, відмов обладнання — випадковість починає шкодити.

Порахуємо. Тестова вибірка на 100 обʼєктів, мінорний клас 2%. Очікувано в ній буде 2 позитивні приклади. Стандартне відхилення цієї кількості — √(100·0,02·0,98) ≈ 1,4. Тобто цілком буденний випадок — нуль позитивних прикладів у тесті. А це означає, що recall не визначений, а вся оцінка перетворюється на лотерею.

Стратифікація прибирає саме цю дисперсію: замість того щоб тасувати все разом, ми тасуємо кожен клас окремо і беремо з нього рівно ту частку, яка потрібна. Пропорція класів у кожній вибірці тоді збігається з пропорцією в усіх даних майже точно.

Інтерактив 4 · Стратифікація при дисбалансі класів

600 випадкових розбиттів і 600 стратифікованих. По горизонталі — яка частка мінорного класу опинилась у тесті.

розкид випадк.
розкид страт.
розбиттів без жодного мінорного
Практика: у scikit-learn це один аргумент — train_test_split(..., stratify=y). Коштує нічого, а прибирає цілий клас проблем. Для регресії стратифікують за квантилями цільової величини.

08 / ПропорціїЯк обирати розміри вибірок

Універсальної відповіді немає, бо ти ділиш обмежений ресурс між двома суперечливими цілями. Кожен обʼєкт, відданий у test, — це обʼєкт, якого недоотримала модель. Кожен обʼєкт, залишений у train, — це втрачена точність вимірювання.

обсяг данихтипове розбиттячому саме так
< 1 000крос-валідаціяокрема валідаційна вибірка вийде надто малою, щоб щось міряти
1 000 — 100 00060 / 20 / 20класика: і вчитись є на чому, і міряти є на чому
> 1 000 00098 / 1 / 11% від мільйона — це 10 000 обʼєктів, а такої вибірки для оцінки вже вистачає

Логіка останнього рядка важлива: розмір відкладених вибірок визначається не часткою, а абсолютною кількістю. Питання завжди одне — скільки обʼєктів потрібно, щоб похибка вимірювання стала прийнятною. Якщо відповідь «десять тисяч», то на мільйоні це один відсоток, а на десяти тисячах — усі сто.

Інтерактив 5 · Розбиття та розкид оцінки

Смуга зверху — пропорції. Гістограма знизу — точність на тесті по 300 різних випадкових розбиттях тих самих даних.

середня точність
розкид (σ)
обʼєктів у test
розмах 5–95%
Спробуй крайні значення: постав train на 85% і validation на 5% — на тест лишиться 20 обʼєктів, і гістограма розповзеться на десятки відсоткових пунктів. Потім постав train на 10%: тепер тесту вдосталь і оцінка стабільна, зате моделі немає на чому вчитись — уся гістограма зсувається вліво. Обидві крайності однаково марні, просто з різних причин.

09 / ПохибкаСкільки коштує мала тестова вибірка

Розкид із попереднього інтерактиву не містить нічого таємничого — його можна порахувати олівцем. Точність на тесті — це частка правильних відповідей серед n незалежних спроб. Кількість успіхів має біноміальний розподіл, а отже стандартна похибка самої частки дорівнює:

SE = √( p(1 − p) / n )

Тут p — справжня точність моделі, n — розмір тестової вибірки. Виведення на два рядки: дисперсія однієї спроби (успіх/невдача) дорівнює p(1−p), дисперсія середнього з n незалежних спроб у n разів менша, корінь дає стандартне відхилення.

крок 1 · одна спроба

Величина «модель вгадала» приймає 1 з імовірністю p і 0 з імовірністю 1−p:

Var = p(1 − p)
крок 2 · середнє з n спроб

Дисперсія середнього незалежних величин ділиться на n:

Var(точність̂) = p(1 − p) / n
крок 3 · довірчий інтервал

При достатньому n розподіл близький до нормального, тож 95% інтервал:

точність̂ ± 1,96 · SE

Ключовий наслідок — корінь у знаменнику. Щоб зменшити похибку вдвічі, вибірку треба збільшити вчетверо. Тому інтуїція «додам ще трохи даних у тест» працює погано: від 100 до 200 обʼєктів похибка падає лише на 30%.

Інтерактив 6 · Стандартна похибка й довірчий інтервал

Крива SE(n) у логарифмічному масштабі. Праворуч — як виглядає 95% інтервал навколо виміряної точності.

SE
95% ДІ ±
n для інтервалу ±1 пп
Практичний висновок: перш ніж радіти, що модель A дала 87%, а модель B 86%, порахуй SE. Якщо тестова вибірка на 200 обʼєктів, похибка близько 2,4 пп — різниця в один пункт просто не існує. Повзунок розміру тут навмисне логарифмічний: подивись, як швидко крива стає майже пласкою.

10 / АльтернативаКоли даних мало: крос-валідація

На маленькому датасеті одна валідаційна вибірка нічого не варта: 15% від 400 обʼєктів — це 60 обʼєктів, і за формулою вище похибка оцінки складе близько 5 пп. Порівнювати на цьому моделі безглуздо.

Розвʼязок — k-кратна крос-валідація. Дані (без тесту!) ділять на k рівних частин. Далі k разів навчають модель на k−1 частинах і міряють на тій, що лишилась. Кожен обʼєкт рівно один раз побував у ролі перевірочного, і жодного разу модель не міряли на тому, на чому вчили. Підсумкова оцінка — середнє з k чисел, а їхній розкид одразу показує, наскільки вона надійна.

Важливо. Крос-валідація замінює валідаційну вибірку, а не тестову. Правильна схема: спочатку відкладаємо test, потім робимо крос-валідацію на решті, обираємо модель, навчаємо її на всіх non-test даних і один раз міряємо на test. Усі перетворення при цьому мусять налаштовуватись усередині кожного фолду — інакше повертається витік зі сценарію 1.

11 / ПідсумокЧекліст перед тим, як довіритись числу

І остання думка, задля якої все це робиться. Розбиття даних — це не бюрократія і не ритуал. Це єдиний доступний нам спосіб змоделювати майбутнє: тестова вибірка вдає із себе дані, яких ще не існує. Наскільки чесно ми зіграємо цю виставу, настільки достовірним буде число, з яким модель піде в реальний світ. Зіпсувати виставу легко — і зазвичай це роблять не зі злого умислу, а через один рядок коду, поставлений на два рядки вище, ніж треба.

Далі в практиці. У practice.ipynb ти реалізуєш розбиття вручну через numpy, порівняєш його зі стратифікованим, відтвориш витік через препроцесинг до розбиття й побачиш його ціну в числах, а потім складеш коректний Pipeline із крос-валідацією.

Далі в темі

Теорію прочитано. Тепер закріпи її на практиці.