Позаду двадцять девʼять тем. Ти вмієш чистити таблицю, робити ознаки, навчати сім різних моделей і міряти їх так, щоб число не брехало. Кожне вміння ти бачив окремо. Тепер зберемо їх в один проєкт — і виявиться, що найважче в ньому не жодне з них, а порядок.
Задача одна на всю тему: детектор шахрайських оголошень на тій самій дошці про вживані телефони, що і в темі 08. 1 200 оголошень, вісім колонок, 16 % шахрайських. Ми пройдемо шлях від сирої таблиці до рішення, чи можна цю модель випускати до людей — з усіма числами й з усіма помилками, які на цьому шляху легко зробити.
ПостановкаПостановка перед кодом
Найважливіший розділ проєкту, і його майже завжди пропускають — бо в ньому немає коду й здається, що все й так зрозуміло. Насправді тут ухвалюються рішення, які потім неможливо переграти.
Чотири питання, на які треба відповісти до першого import.
Що саме передбачаємо і в який момент. Не «шахрайство взагалі», а: чи є це оголошення шахрайським у мить публікації, до того, як на нього хтось відгукнувся. Друга половина речення важливіша за першу: вона одразу викидає з ознак усе, чого в цю мить іще не існує.
Кому потрібен прогноз і що він із ним зробить. Модератор дошки. Він не читає всі оголошення підряд — він читає ті, які модель підняла нагору. Отже, прогноз має бути не «так/ні», а чергою, і в неї є пропускна здатність: скільки оголошень людина встигає перевірити за день.
Скільки коштує помилка кожного типу. Ось де ця задача перестає бути симетричною.
Ціна двох помилок
Обидві помилки коштують грошей, але платять за них різні люди й у різний спосіб.
| помилка | хто платить | чим це закінчується | чи можна виправити |
|---|---|---|---|
| Пропустили шахрая | покупець | втрачена передоплата, скарга, публічний допис «вас обдурили» | ні — гроші вже пішли |
| Хибна тривога | чесний продавець і модератор | оголошення затримано, людину образили, витрачено час перевірки | так — якщо є куди поскаржитись |
Яка з цього метрика. Точність (accuracy) тут не годиться взагалі: шахрайських оголошень 16 %, тож константа «всі чесні» дає 84 % і не знаходить нікого (тема 05). Нам потрібні дві величини одночасно — скільки шахраїв упіймали (recall) і яка частка тривог виявилась справжньою (precision). Щоб порівнювати кроки одним числом, беремо F1 — їхнє гармонійне середнє.
Правило переходу до кроку 2. Далі йдемо тільки тоді, коли всі чотири відповіді записані текстом — у файлі проєкту, а не в голові. Перевірка проста: дай прочитати ці десять рядків людині, яка задачі не бачила, і спитай, що саме передбачає модель і чим погана кожна з двох помилок. Якщо вона переказала — постановка готова.
ПоділПоділ — перша дія
Друга дія проєкту — і теж без жодної моделі. Ще до того, як подивитись на розподіли, порахувати пропуски й побудувати хоч одну гістограму, ми відкладаємо 25 % рядків і більше їх не чіпаємо.
Чому саме тут, а не після розвідки? Бо розвідка змінює тебе. Ти побачив, що ціна має довгий хвіст — і вирішив узяти логарифм. Побачив чотири дивні рядки — і вирішив їх прибрати. Кожне таке рішення підігнане під ті дані, які ти бачив. Якщо серед них був і тест, то тест перестав бути незалежним ще до першого навчання (тема 03). Модель нічого не підглядала, зате підглянув ти — і результат той самий.
stratify тут не прикраса. Шахрайських оголошень 195 із 1 200; без
стратифікації їхня частка в тесті гуляє на кілька відсотків просто від жеребкування, і
різниця між двома моделями потоне в цьому шумі. З нею частка однакова в обох частинах:
16.2 % і 16.3 %.
Дві речі можна зробити до поділу, бо вони не рахують із даних жодного числа:
привести памʼять до одного запису (128 замість 128 ГБ) і
прибрати повні дублікати рядків. Дублікати — саме до поділу: якщо той
самий рядок потрапить і в навчальну, і в тестову частину, тест перевірятиме модель на
тому, що вона вже бачила напамʼять. А от медіани, межі викидів і заповнення пропусків —
тільки після (тема 09).
Саме тут таблиця й міняє розмір. У вигрузці з дошки 1 212 рядків; повних дублікатів серед них дванадцять, і після їх видалення лишається рівно 1 200. Це те число, з яким працює вся тема: 1 200 = 900 навчальних + 300 відкладених. Дванадцять рядків — дрібниця для розміру вибірки й не дрібниця для чесності заміру: кожен дубль, що розʼїхався по обидва боки поділу, підняв би тестове число задарма.
Правило переходу до кроку 3. Тестова частина лежить в окремій змінній, і далі в коді немає жодного рядка, який до неї звертається. Поки такий рядок є — розвідку не починають, бо будь-яке число, пораховане по всіх 1 200, уже забруднене.
Порядок дій і три місця, де ховається витік
Вісім кроків проєкту в порядку виконання. Тестова частина замкнена від кроку 2 до кроку 7.
РозвідкаРозвідка: три відповіді
Повний розбір цієї таблиці зроблено в темі 08, і повторювати його тут нема сенсу. Нам потрібні три відповіді, від яких залежать подальші рішення — і всі три рахуються тільки на 900 навчальних рядках.
Слово «тільки» тут не обережність, а те саме правило, що й у
темі 03 і
темі 09, лише в найширшій формі. Витік
— це будь-який шлях, яким знання про тестові рядки потрапляє в рішення. Медіана,
порахована по всіх 1 200, — витік у коді. Гістограма, побудована по всіх 1 200 і
побачена тобою, — витік у голові, і він не менш реальний, просто його не видно в
git diff. Обидва завищують кінцеве число, і обидва лікуються однією
звичкою: усе, що дивиться на дані, дивиться тільки на 900.
Перша: де пропуски й чи вони випадкові. Ціни немає у 72 рядках, стану — у 30. І пропуск у ціні аж ніяк не випадковий: серед рядків без ціни шахрайських 54.2 %, серед рядків із ціною — 12.9 %. Отже, ці рядки не викидають: відсутність ціни сама по собі є сигналом, і їй потрібен окремий прапорець (тема 09).
Друга: чи немає колонки, якої в момент прогнозу ще не існує. Це питання ставлять числом. Кореляція кожної колонки з таргетом:
Колонка скарг має лякати, а не радувати. Скарги зʼявляються після
публікації, коли шахрая вже викрили; у мить, коли модель має відповісти, там нуль у всіх.
Це витік, і коштує він дорого: модель зі
скарг дає F1 0.974 на крос-валідації і нуль у бою. Колонку
викидаємо назавжди — і з навчальної частини, і з тестової.
Третя: що з викидами. Найдорожче оголошення в навчальній частині —
95 000 грн. Це не помилка даних у чистому вигляді: чотири рядки — колекційні
Gamma X 2017 року, а ще два — одруки із зайвим нулем. Ми їх поки не чіпаємо
й побачимо у розділі 7, у що це вилилось.
ВідлікБазова лінія
Перш ніж навчати будь-що, треба знати, з чим порівнювати. DummyClassifier
зі стратегією most_frequent завжди відповідає «чесне» й на ознаки не
дивиться взагалі:
Дві цифри в одному рядку — і вони описують ту саму модель. Вона не помиляється у 84 % випадків і не знаходить жодного шахрая. Ось чому accuracy тут не метрика, а декорація: щоб отримати 84 %, не треба нічого вміти.
Тепер уяви звіт «наша модель має точність 94 %». Без другої половини — «а базова лінія дає 84 %» — перша не читається. Правильна форма звіту завжди подвійна (тема 29).
Базова лінія робить ще одну роботу, менш очевидну: вона перевіряє сам конвеєр. Якщо
DummyClassifier у твоєму коді падає, дає нечисла або показує F1 = 0.7 — то
зламано не модель, а щось до неї: розмітка, поділ або підрахунок метрики. Дешевше
знайти це на моделі з нуля рядків логіки, ніж через два дні на градієнтному бустингу.
Правило переходу до кроку 5. Два числа базової лінії записані у звіт (0.838 і 0.000), і будь-яке наступне число з цієї миті наводиться в парі з ними. Одинарне число зі звіту викидаємо — воно нічого не означає.
Перша модельПерша чесна модель
Не найкраща — перша. Логістична регресія (тема 14) на вихідних стовпцях, усередині конвеєра, з пʼятиразовою крос-валідацією.
Конвеєр (Pipeline) тут не для краси. Усередині нього закриваються
пропуски, масштабуються числа й кодуються категорії — і все це рахується заново на
кожному фолді крос-валідації, окремо для навчальної частини фолда. Якщо винести
підготовку назовні, медіана для заповнення пропусків буде порахована по всіх 900 рядках,
зокрема й по тих, на яких модель зараз перевіряють. Число підросте, а причини цього
в коді буде не видно (тема 09).
Це не результат, це його відсутність. І тут працює правило з теми 29: якщо проста модель не відірвалась від базової лінії, справа майже напевно в даних, а не в алгоритмі. Складніший алгоритм не знайде того, чого в стовпцях немає.
А ми знаємо, чого саме немає. «Ціна 1 310 грн» не означає нічого, поки не сказано, скільки коштує такий самий телефон (тема 10). Будуємо цю ознаку — медіанну ціну всередині групи «модель + рік», а далі модуль логарифма відношення:
Карту типових цін рахуємо тільки на навчальній частині й потім застосовуємо до тестової як готовий довідник. Таргет у цій карті не бере участі — це медіана ціни, а не частка шахрайських, — тому витоку відповіді тут немає. Але звичка рахувати все на train дешевша за звичку щоразу згадувати, чи можна цього разу зробити інакше.
ІтераціїІтерації, зокрема невдалі
Далі починається те, що й займає більшу частину часу: цикл «одна зміна — одне число». Правило просте й нудне: за раз змінюємо рівно одну річ. Дві зміни разом дають одне число, з якого неможливо зрозуміти, що саме спрацювало.
Шлях проєкту з числами
Проведи повзунок від першого кроку до останнього. Один зі стовпчиків нижчий за попередній, а останній — нижчий за передостанній. Обидва провали справжні.
Розберемо, що сталось на кожному кроці.
Крок 2, ознака: 0.013 → 0.835. Один стовпчик, зроблений із двох чисел, які вже були в таблиці. Жодних нових даних, жодної складнішої моделі. Це найбільший приріст усього проєкту, і так буває майже завжди.
Крок 3, інша модель: 0.835 → 0.804. Хід був очевидний: випадковий ліс бачить нелінійності й взаємодії, працює зі значеннями за замовчуванням, не боїться масштабу. Мав виграти — і програв. Причина видима, коли її вже знаєш: розділювальна межа тут майже пряма («відхилення більше за поріг — шахрай»), а ламана межа з дерев таку пряму лише наслідує, щоразу трохи промахуючись.
Крок 4, налаштування: 0.835 → 0.844. Шість поєднань
C і class_weight перебором
(тема 20). Приріст є — і порівняй його
з попереднім: ознака дала 0.835 − 0.013 = 0.822, налаштування дало
0.844 − 0.835 = 0.009. Це у 91 раз менше при тому, що на перебір пішло
більше машинного часу, ніж на ознаку. Пропорція нормальна, і вона підказує, куди
вкладати наступну годину: у дані, а не в ручки.
Зверни увагу на ще одну деталь кроку 4: налаштовували ми логістичну, а не ліс. Невдалий крок 3 із гілки випав — його не «покращують», а закривають. Тому й приріст 0.009 рахується від 0.835, а не від 0.804: остання прийнята точка гілки — це та, з якої проєкт рушив далі, а не та, яку зробили останньою за часом.
ПомилкиПомилки очима
Метрика каже, скільки помилок. Вона ніколи не каже, які. Тому після кожного серйозного кроку варто відкрити самі рядки, на яких модель помилилась.
«Подивись на помилки» — порада, з якою нічого не зробиш. Ось та сама порада у вигляді пʼяти дій, які можна виконати по черзі.
- Візьми прогнози, яких модель не підглядала.
cross_val_predictвіддає для кожного з 900 оголошень прогноз тієї моделі, у навчанні якої це оголошення не брало участі. Не прогноз навченої моделі на її ж даних — на них помилок майже немає, і дивитись нема на що. І не тест: він закритий. - Розклади рядки на чотири купи — спіймані шахраї, пропущені шахраї, хибні тривоги, чесні названі чесними — і запиши розмір кожної. У нас: 122, 24, 21 і 733. Дві середні купи — це і є всі 45 помилок проєкту.
- Порахуй у кожній купі те саме, що рахував по всій вибірці: медіану головної ознаки, частку пропусків, медіанний вік акаунта. Стовпчик, у якому число різко вибивається, і є підказкою. Саме так знайшлась перша знахідка: пропусків ціни в помилках 62 %, а в усій вибірці 8 %.
- Відкрий руками десяток окремих рядків із найбільшою впевненістю моделі — тих, де вона помилилась голосно. Числа показують, де проблема; сирі рядки показують, яка вона.
- Назви причину і поклади її в один із трьох кошиків: це дефект даних (лікується на вході, до моделі), брак ознаки (лікується наступною ітерацією) або межа задачі (лікується рішенням про продукт, а не кодом). Кошик визначає, хто це робить і скільки це коштує.
Далі — дві знахідки, які ця процедура дала на нашій дошці, по одній із двох різних кошиків.
Що спільного в помилок
900 навчальних оголошень. Ліворуч від риски — ті, у яких ціни немає взагалі. Перемикай групу й дивись, куди вона збирається.
Обидві групи помилок помітно зміщені в смугу ліворуч від риски. Порахуємо це прямо: помилок усього 45, з них 28 (62 %) — на оголошеннях без ціни. А самих таких оголошень 72 з 900, тобто 8 %. Вісім відсотків даних дають шістдесят два відсотки помилок.
Причина зрозуміла, щойно її побачив: головна ознака побудована з ціни, а тут ціни немає — і серед цих рядків шахрайських 54 %, тобто майже підкидання монети. Жодна нова ознака цього не виправить, бо в цих рядках просто немає сигналу. Це не задача для моделі, а рішення про продукт, і ми до нього повернемось.
Друга знахідка — у хибних тривогах, де ціна таки є. Їх пʼять, і три ми вже бачили:
два Gamma X 2017 року за 82 і 88 тисяч (ті самі колекційні з
теми 08) і Gamma X Ultra за
76 000 грн — одрук із зайвим нулем, справжня ціна 7 600. Модель робить рівно те, чого ми
її навчили: бачить ціну в 12-17 разів вищу за типову й кричить «шахрай».
Правильна відповідь тут — не нова ознака. Ловити три рядки окремим правилом означає вчити модель на брудних даних. Правильно — виправити дані на вході: завести на дошці категорію «колекційне» й перевірку на порядок величини у формі подання оголошення. Цього не видно з жодної метрики і видно за пʼять хвилин, якщо просто відкрити рядки.
Коли цикл зупиняють
Ітерації не закінчуються самі. Питання «а може, ще одна ідея?» має відповідь «так» завжди, тому момент зупинки треба призначити правилом, а не настроєм. Робочих сигналів три, і достатньо будь-якого.
- Приріст став меншим за розкид самого заміру. Крос-валідація дає не число, а число з розкидом. У темі 18 пʼять фолдів дали 0.81, 0.86, 0.79, 0.88 і 0.84: середнє 0.836 при стандартному відхиленні 0.033 — тобто саме́ це середнє гуляє сильніше, ніж багато «приростів». Звідти й правило: різниця між двома моделями щось означає лише тоді, коли вона більша за розкид оцінки. Наш крок 4 дав +0.009 і жодного ± поруч — це привід зупинитись, а не доказ приросту.
- Аналіз помилок більше не називає нової причини. Якщо процедура з пʼяти дій приводить туди ж, де ти вже був, — сигналу в даних більше нема, і чергова ознака буде вгадуванням.
- Наступна ідея коштує дорожче за виграш. Приріст 0.009 ціною тижня роботи — це рішення про гроші, а не про метрику, і ухвалює його не той, хто пише код.
У нашому проєкті спрацювали перші два одночасно. Тому цикл закривається, і відкривається сейф.
cross_val_score(...).mean() разом зі
.std(). Одне число без розкиду вирішує суперечку між двома близькими
моделями підкиданням монети.ФіналФінальний замір
Ознаки обрано, модель обрано, гіперпараметри підібрано, поріг визначено — усе це на крос-валідації, і поріг теж: як саме його обирали, розберемо в розділі 9, але обрано його до цієї миті. Тепер навчаємо на всіх 900 рядках і міряємо на 300 відкладених. Один раз.
Тест нижчий на 0.048, і це не збіг і не невдача. Ми обирали ознаку, модель, гіперпараметри й поріг за числом крос-валідації — а те, що обирали максимізуванням, завжди виходить трохи завищеним (тема 20). Шість поєднань у сітці — шість спроб, і найкраще з шести чисел уже містить дрібку везіння. Тест цього відбору не бачив, тому й показує менше.
Правильне очікування якості в бою — 0.796, а не 0.844. І перше, що хочеться зробити з цим числом, — покращити його ще однією ідеєю та поміряти знову. Цього робити не можна: другий погляд на тест перетворює його на ще одну перевірочну вибірку, і чесного числа в проєкті не лишається взагалі.
ЗапускЧи можна це запускати
Тут закінчується технічна частина. Далі — рішення, і жодне з них не має відповіді в коді.
Почнемо з того, що модель віддає не «так/ні», а ймовірність. Рішення підіймати тривогу ухвалює поріг, і 0.5 — це не закон природи, а значення з коробки (тема 21). Поріг — теж рішення, тож обирають його там само, де й усі інші: на крос-валідації, а не на тесті. Подивись, у що перетворюється кожен поріг у наслідках задачі.
Поріг рішення в наслідках, а не в метриках
Дві криві: скільки шахраїв проходить повз і скільки чесних продавців даремно потурбовано. Проведи повзунок від краю до краю.
Тепер повернімось до знахідки з розділу 7. Гіпотезу «якість тримається на оголошеннях із ціною» ми сформулювали на навчальній частині, до того, як відкрили сейф. Тому розкласти той самий єдиний замір на дві підгрупи — не другий погляд на тест, а докладніший запис першого: рядки ті самі 300, прогнози ті самі, модель після цього не змінюється. Видно:
Отже рішення про запуск не одне, а два. Оголошення з ціною — 91 % потоку — модель вирішує сама: з 28 піднятих тривог 27 виявились справжніми. Оголошення без ціни йдуть у чергу до модератора без моделі; не тому, що модель погана, а тому, що в цих рядках немає з чого робити висновок. Розділити задачу — теж інженерне рішення, і часто краще за спроби витиснути ще 0.01 з метрики.
Далі — чотири питання, які вирішує не той, хто пише код.
Рішення про запуск і на що воно впливає
Жодне з цих рішень не міняє F1. Кожне міняє те, чим модель обернеться для людей.
| рішення | варіанти | на що впливає |
|---|---|---|
| Що система робить із тривогою | блокувати · показати попередження · підняти в черзі модератора | ціну хибної тривоги — від «нічого» до «чесний продавець пішов на іншу дошку» |
| Хто перевіряє чергу і скільки встигає | один модератор · команда · автоматично понад порогом 0.95 | поріг: пропускна здатність людей задає, скільки тривог має сенс піднімати |
| Як оскаржити рішення | кнопка «це помилка» · лист у підтримку · ніяк | і довіру, і дані: скарги на хибні тривоги — це нова розмітка |
| Як міряємо якість після запуску | щотижневий замір на свіжій розмітці · дивимось на скарги · ніяк | чи помітимо взагалі, що модель зіпсувалась |
І головне, чого не показує жодне число з цієї теми: модель у продакшні деградує. Завжди. Карта типових цін застаріває, бо телефони дешевшають і зʼявляються нові моделі. Шахраї змінюють поведінку — саме тому, що їх почали ловити: детектор, навчений на «дешева приманка», перестане працювати того дня, коли вони почнуть ставити ціну біля типової. Модель, яку запустили й забули, — це не запущена модель, а запущена й покинута.
ЧеклістЧекліст проєкту
Найпрактичніше, що можна забрати з цієї теми, — не число й не прийом, а порядок. Ось він цілком, у вигляді, придатному для друку й прикріплення над столом.
Чекліст наскрізного проєкту
Шість груп у порядку виконання: зліва направо, згори вниз. Пропущений пункт із верхніх груп коштує дорожче за будь-який із нижніх.
ДаліЩо далі
Озирнись: ти почав із питання «що таке машинне навчання», а закінчуєш проєктом, у якому є постановка, чесна оцінка й обґрунтоване рішення про запуск. Між цими двома точками — сім моделей, десяток метрик і одна звичка, яка важить більше за все інше: не вірити числу, поки не знаєш, як воно пораховане.
Цей проєкт спирався на одне припущення, яке ми жодного разу не назвали вголос:
у нас є правильні відповіді. Колонка шахрайське була в таблиці з
самого початку — хтось її розмітив, і саме тому ми могли порахувати F1. Курс уже показав,
що робити, коли такої колонки немає: кластеризація,
ієрархічна та DBSCAN,
пошук аномалій і
зменшення розмірності працюють без жодної
відповіді. Порядок дій із цієї теми на них теж поширюється — крім тих кроків, які без
міток просто нема на чому виконати: базової лінії за F1 і чесного тесту. Це, до речі,
головна причина, чому задачі без учителя важчі, а не легші.
Чого цей проєкт не покриває
Чесний проєкт закінчується не переліком перемог, а переліком того, чого в ньому немає. У нашому немає пʼяти речей, і кожна з них — окрема робота.
- Часу. Поділ у нас випадковий, а оголошення приходять у часі. Випадковий поділ мовчки припускає, що завтрашні дані схожі на вчорашні; шахраї цього припущення не поділяють. Чесніше — ділити за датою: навчатись на старіших, міряти на новіших.
- Розкиду. Усі числа наведені як одне середнє по пʼяти фолдах, без ±. І весь
поділ стоїть на одному жеребкуванні —
random_state=42. Скільки з різниці 0.844 проти 0.796 припадає на це єдине число, ми не міряли. - Грошей. Ми сказали, що recall дорожчий за precision, але не сказали у скільки разів. Поки ціна пропущеного шахрая й ціна образленого продавця не названі в гривнях, поріг обирається за F1 — тобто за припущенням, що вони рівноцінні. Це припущення майже напевно неправильне.
- Справедливості. Ми жодного разу не спитали, чи однаково модель помиляється на різних групах продавців — новачках і старожилах, дешевому й дорогому сегменті. Середній F1 таке питання ховає повністю (тема 38).
- Життя після запуску. Модель у продакшні деградує, і всі числа цієї теми — знімок одного дня. Що з цим робити — тема 31, наступна.
А далі за нею — перцептрон і нейронні мережі, які починаються там, де таблиця закінчується: текст, звук, зображення. Вони не скасовують нічого з того, що ти щойно пройшов. Поділ, базова лінія, чесний тест і аналіз помилок там точно такі самі — просто модель усередині складніша.