Та сама дошка оголошень про вживані телефони, та сама задача: відрізнити приманку від чесного продавця. Але цього разу ми не дивимось ні на ціну, ні на вік акаунта — ми читаємо текст оголошення й питаємо, чи видають шахрая слова, які він обрав.
У попередній темі моделлю працювала сама таблиця: kNN нічого не узагальнював і на кожен запит перебирав архів заново. Метод цієї теми піде протилежним шляхом — прочитає архів один раз, зведе його до кількох десятків ймовірностей і саму таблицю викине.
01 / РозворотПитання навпаки
Візьмемо архів дошки — оголошення, про кожне з яких уже відомо, чим воно закінчилось, — і порахуємо, як часто в тексті приманки трапляється слово «передоплата». Нехай вийшло 75%. А тепер спитаємо те, що насправді потрібно модератору: прийшло нове оголошення зі словом «передоплата» — яка ймовірність, що воно шахрайське?
Це інше питання, і відповідь у нього інша. Перше рахує частку слова серед шахраїв, друге — частку шахраїв серед тих, хто написав слово.
- Що ми вміємо порахувати:
P(слово | шахрайство)— «ймовірність слова за умови, що оголошення шахрайське». Це наші 75%. - Що нам потрібно:
P(шахрайство | слово)— частка шахрайських серед оголошень зі словом.
Вертикальна риска читається як «за умови»: зліва стоїть подія, ймовірність якої нас цікавить, справа — те, що ми вже знаємо. Місцями їх переставити не можна.
P(квиток | виграш) = 1. З цього ніяк не випливає, що всі,
хто купив квиток, виграли — P(виграш | квиток) становить мільйонні частки.
Однакові слова, протилежні за розміром відповіді.Плутанина між цими двома числами трапляється щодня — у новинах, у медичних висновках, у звітах про роботу моделей. Правило, яке дозволяє чесно перевернути перше число на друге, і називається теоремою Баєса. Але перш ніж писати формулу, порахуємо все на пальцях.
02 / ТеоремаСто оголошень, чотири клітинки
Візьмемо з архіву рівно сто оголошень — щоб частки одразу читались як відсотки. Про кожне відомо дві речі: чим воно виявилось і чи є в його тексті слово «передоплата». Отже, кожне потрапляє в одну з чотирьох клітинок.
Схема 1 · Сто оголошень і слово «передоплата»
Кожен квадратик — одне оголошення з архіву. Ті самі сто квадратиків читаються двома різними способами, і числа виходять різні.
Тепер обидва питання з розділу 1 стають арифметикою, яку видно очима.
Скільки шахрайських оголошень пишуть «передоплата»? Дивимось лише на ліву колонку: усього шахрайських 28, слово є у 21 з них.
Прийшло оголошення зі словом. Дивимось лише на верхній рядок: таких оголошень усього 27, шахрайських серед них 21.
Чисельник в обох дробах один і той самий — 21 оголошення в перетині. Змінився знаменник: спершу ділили на «усі шахрайські», потім на «усі зі словом». Перевернути питання означає рівно одне: поміняти групу, всередині якої рахуєш частку.
Ось і все, що робить теорема Баєса. Тепер запишемо ту саму дію формулою. Замість «21» напишемо, звідки воно взялось: із 28 шахрайських слово мають 75%, тобто 28 × 0.75. А замість «27» — частку оголошень зі словом від усієї сотні.
P(слово)
Три позначення в правій частині, і кожне вже зустрічалось у нашій таблиці:
| символ | як зветься | що це в нашій таблиці | число |
|---|---|---|---|
| P(шахрайство) | апріорна ймовірність | частка шахрайських серед усіх ста оголошень — те, що ми думали до прочитання тексту | 28 / 100 = 0.28 |
| P(слово | шахрайство) | правдоподібність | як часто слово трапляється в шахрайських оголошеннях | 21 / 28 = 0.75 |
| P(слово) | ймовірність свідчення | як часто слово трапляється взагалі, у будь-якому оголошенні | 27 / 100 = 0.27 |
| P(шахрайство | слово) | апостеріорна ймовірність | чого ми хочемо: частка шахрайських серед оголошень зі словом | шукане |
Слова «апріорна» й «апостеріорна» означають просто «до» й «після»: до того, як ми побачили текст, і після. Підставляємо:
Те саме число 0.78, що ми отримали, просто порахувавши квадратики. Формула лише
записала ту саму дію так, щоб її можна було виконати без намальованої сітки. І тепер
видно, що вона робить: бере початкове уявлення P(шахрайство) = 0.28
й оновлює його новим фактом до 0.78.
P(чесне | слово) = P(слово | чесне) · P(чесне) / P(слово).
Знаменник у них однаковий, тож для порівняння двох варіантів його можна викинути —
достатньо порівняти чисельники. Саме так модель і рахуватиме далі, а P(слово)
з'явиться лише в кінці, коли треба перетворити два числа у відсотки.03 / АпріорнаЧому вирішує те, що було до
Тепер найважливіший розділ теми. У формулі є множник P(шахрайство) —
частка шахраїв на дошці до будь-яких свідчень. Здається, це дрібниця поруч із
«надійністю ознаки». Насправді часто саме він і вирішує відповідь.
Уяви іншу категорію тієї самої дошки — продаж ноутбуків, де шахраїв менше: не 28, а 10 зі ста. І нехай ознака дуже пристойна: вона спрацьовує на 8 із 10 шахраїв і помиляється лише на 2 із 10 чесних. Порахуємо на сотні оголошень.
Шахрайських 10, чесних 90.
Серед 10 шахраїв — на 80%, тобто на 8. Серед 90 чесних — на 20%, тобто на 18.
Ознака спрацювала — а шахрайство все одно ймовірніше ні, ніж так: двоє з кожних трьох спрацювань є хибною тривогою.
Причина не в тому, що ознака погана, а в тому, що чесних більше. Ознака помиляється рідко — лише на кожному п'ятому чесному, — але чесних дев'яносто, і 20% від дев'яноста більше, ніж 80% від десяти. Рідкісний клас програє арифметично: невеликий відсоток помилок на великій групі дає більше хибних спрацювань, ніж уся мала група разом узята.
Ефект тим сильніший, чим рідкісніша знахідка. Якби шахраїв було 20 на тисячу оголошень, а ознака була аж на 95% надійною, спрацювань було б 19 справжніх плюс 49 хибних — тобто лише 19 / 68 = 28%. Ознака стала надійнішою, а впевненість — навіть нижчою, бо клас став рідкіснішим.
Інтерактив 1 · Теорема Баєса на сотні оголошень
Сто квадратиків — сто оголошень. Верхній повзунок вирішує, скільки з них шахрайські; нижній — наскільки надійна ознака. Дивись, з чого складається стовпчик спрацювань праворуч.
04 / НаївністьЧому «наївний»
Оголошення складається з багатьох слів. Візьмемо фіксований словник із семи, які реально трапляються на дошці, і порахуємо по архіву, у скількох оголошеннях кожного класу вони зустрічаються.
| слово | у шахрайських (28) | у чесних (72) | куди тягне |
|---|---|---|---|
| терміново | 19 | 9 | до шахрайства |
| передоплата | 21 | 6 | до шахрайства |
| дешево | 16 | 11 | до шахрайства |
| новий | 8 | 28 | до чесності |
| торг | 7 | 33 | до чесності |
| гарантія | 3 | 26 | до чесності |
| чек | 0 | 31 | до чесності |
Тепер треба об'єднати свідчення кількох слів. І тут з'являється припущення, від якого метод отримав своє ім'я. Модель рахує ймовірність цілого тексту як добуток ймовірностей окремих слів:
Перемножувати ймовірності можна тільки тоді, коли події незалежні — коли знання про одну не змінює ймовірності іншої. Модель мовчки припускає, що це так: що всередині класу слова розкидані по текстах незалежно, ніби автор кидав окрему монетку на кожне слово. Це припущення й називають наївним. Воно хибне — перевіримо просто на нашому архіві.
Схема 2 · Незалежність, якої немає
28 шахрайських оголошень, розкладені за наявністю двох слів. Ліворуч — як насправді, праворуч — як їх бачить модель, яка вважає слова незалежними.
Наслідок такий. Побачивши обидва слова, модель множить два свідчення так, ніби це дві незалежні новини. Насправді друга майже не додає інформації до першої: вона й так була очікувана. Модель рахує одне свідчення двічі й виходить самовпевненішою, ніж має право бути. Її ймовірності зсуваються до країв: там, де чесна оцінка сказала б «десь 80%», наївний Баєс легко видасть 0.99.
І попри це метод усе одно працює — бо для рішення потрібне не точне значення ймовірності, а лише те, який із двох добутків більший. Перекошені в обидві сторони множники часто зберігають правильний порядок, навіть коли самі числа брехливі.
predict варто брати всерйоз, його
predict_proba — ні. Якщо ймовірність потрібна саме як число (щоб рахувати
очікувані збитки), її доводиться калібрувати окремо — CalibratedClassifierCV
у scikit-learn. У логістичної
регресії такої біди немає: вона вчиться саме на ймовірностях.Тримай цю думку окремо, вона ширша за тему: модель може бути корисною, будучи неправильною. Питання не в тому, чи правдива модель, а в тому, чи достатньо вона правдива для рішення, яке ти нею ухвалюєш.
05 / ОбчисленняЯк рахується вирок
Пройдемо повне обчислення для одного конкретного оголошення. Текст: «Терміново продам, новий, лише передоплата». Зі словника в ньому три слова: терміново, новий, передоплата — і тягнуть вони в різні боки, бо «новий» частіше буває в чесних.
Модель рахує два числа й порівнює їх. Кожне — апріорна ймовірність класу, помножена на ймовірності всіх слів тексту в цьому класі:
Ймовірність слова в класі — це його частка серед усіх слів словника, порахованих у текстах класу. У шахрайських оголошеннях сім наших слів трапились разом 74 рази, у чесних — 144. Це і будуть знаменники.
Стартова позиція: якби текст був порожній, ми б відповіли «чесне».
Перше число більше за друге у 6.05 раза, отже вирок —
шахрайство. Щоб перевести це у відсотки, ділимо на суму обох
(це і є пропущений знаменник P(текст)):
Подивись на роботу окремих слів. «Терміново» подіяло як множник 0.2568 / 0.0625 = 4.1 на користь шахрайства, «передоплата» — як 6.8. А «новий» тягнув у протилежний бік із множником 0.1081 / 0.1944 = 0.56, майже вдвічі гасячи підозру. Разом із апріорним співвідношенням 0.28 / 0.72 = 0.39 це й дало підсумкові 6.05.
Інтерактив 2 · Що важить кожне слово
Вмикай і вимикай слова в тексті оголошення — два добутки й підсумкова ймовірність перераховуються наживо. Слово «чек» тут відсутнє навмисно: воно ламає обчислення, і саме цим займеться наступний розділ.
Слова додаються незалежно одне від одного, і порядок їх не цікавить: наївний Баєс бачить не текст, а мішок слів (bag of words) — які слова є і скільки разів. «Гарантія без передоплати» і «передоплата без гарантії» для нього те саме оголошення.
06 / Дві деталіНуль і ще один нуль
Метод, як ми його описали, у чистому вигляді не працює. Дві деталі, обидві про нулі, обидві обов'язкові.
Деталь перша: слово, якого не було
У таблиці розділу 4 слово «чек» у шахрайських оголошеннях трапилось нуль разів — приманки не пропонують чек. Порахуємо оголошення «Терміново, лише передоплата, дешево, є чек», де три перших слова — сильні сигнали шахрайства:
Добуток обнулився. Скільки б інших слів не кричало «шахрайство», один множник-нуль з'їдає їх усі, і модель із абсолютною впевненістю каже «чесне». Слово, якого просто не виявилось у навчальній вибірці, накладає вето на всі інші свідчення.
Лікування — згладжування Лапласа (Laplace smoothing, воно ж add-one
smoothing). До кожного лічильника додаємо однакове маленьке число α, а до
знаменника — α, помножене на розмір словника, щоб сума ймовірностей лишилась
одиницею:
усього слів у класі + α · розмір словника
Словник має 7 слів, тож при α = 1 знаменник шахрайського класу стає
74 + 7 = 81, а чесного — 144 + 7 = 151. Ймовірність «чека» в шахраїв уже не нуль,
а 1/81 = 0.0123. Мало, але не смертельно.
α означає ось що: ми вдаємо, що перед підрахунком
кожне слово словника вже один раз трапилось у кожному класі. Це страховка від твердження
«такого не буває ніколи», зробленого на підставі скінченної вибірки: того, чого ти не
бачив, ти не бачив — це ще не доказ неможливості. α — гіперпараметр,
у scikit-learn це аргумент alpha, за замовчуванням 1.0.Інтерактив 3 · Згладжування Лапласа
Оголошення «Терміново, лише передоплата, дешево, є чек». Три слова кричать «шахрайство», четверте не траплялось у шахраїв жодного разу. Посунь α до нуля.
Деталь друга: добуток провалюється в нуль сам
Другий нуль підступніший, бо виникає без жодного нульового множника. Наш приклад мав три слова, і добуток вийшов 0.0022. А справжній текстовий класифікатор працює зі словником у десятки тисяч слів, і лист легко містить дві-три сотні — кожне з множником менше за одиницю.
Нехай у тексті 300 слів і кожне має ймовірність близько 0.01. Добуток дорівнює
0.01300 — число з трьомастами нулями після коми. А найменше
додатне число, яке вміщається у тип float64, — приблизно
5·10−324. Добуток провалюється в машинний нуль на
162-му слові, і далі обидва класи дають рівно 0.0. Порівнювати нічого.
Схема 3 · Чому добуток замінюють сумою
Ліворуч — добуток ймовірностей слово за словом. Праворуч — той самий рахунок у логарифмах. Вертикальна шкала однакова за змістом, різна за поведінкою.
float64 і на
162-му слові стає точним нулем — після цього обидва класи невідрізнимі.
Праворуч та сама величина в логарифмах спадає рівною прямою: після 300 слів це
всього лише −1382.Вихід — рахувати не добуток, а суму логарифмів. Логарифм перетворює множення на додавання:
Замість тисячі множень крихітних чисел — тисяча додавань чисел порядку одиниць.
Порівняння при цьому не псується: логарифм зростає, тож більшому добутку відповідає
більший логарифм. А що вирок ми ухвалюємо саме порівнянням, нам більше нічого й не
треба. Саме тому всередині scikit-learn усі обчислення йдуть у логарифмах,
а назовні є метод predict_log_proba.
07 / РізновидиТри Баєси на одній дошці
Досі ми рахували частоти слів. Але ознаки бувають різні, і різниця між різновидами наївного Баєса рівно одна: як саме модель описує ознаку всередині класу. Решта — та сама теорема, той самий добуток, ті самі апріорні ймовірності.
Схема 4 · Три різновиди й де кожен доречний
Один метод, три способи оцінити P(ознака | клас). Приклади — з нашої дошки оголошень.
| мультиноміальний | гаусів | бернуллі | |
|---|---|---|---|
| клас у sklearn | MultinomialNB | GaussianNB | BernoulliNB |
| ознака | лічильник: скільки разів | число на шкалі | прапорець: є / нема |
| що зберігає | частоту кожного слова в класі | середнє й розкид кожної ознаки в класі | частку об'єктів класу з ознакою |
| приклад із дошки | скільки разів у тексті слово «терміново» | відносна ціна й вік акаунта | чи є в оголошенні фото, чи вказано IMEI |
| сильна сторона | довгі тексти, де важлива частота | числові ознаки без перетворень | короткі тексти, де важлива сама наявність |
| де ламається | ознака може бути лише невід'ємною | ознака в класі має бути одногорбою | губить інформацію про кількість |
Найцікавіший тут гаусів, бо його можна запустити на тих самих даних, що й kNN у попередній темі: відносна ціна й вік акаунта. Для кожного класу й кожної ознаки він рахує рівно два числа — середнє й стандартне відхилення — і далі вважає, що ознака в цьому класі розподілена за нормальним законом («дзвоном») із цими параметрами. На наших даних вийшло так:
| клас | відносна ціна | вік акаунта, днів |
|---|---|---|
| чесні | 0.905 ± 0.343 | 220 ± 94 |
| шахрайські | 0.724 ± 0.288 | 88 ± 77 |
Вісім чисел плюс дві апріорні ймовірності — і це вся модель. Навчальна таблиця на 360 рядків після цього не потрібна, тоді як kNN мусив тримати всі 360 рядків у пам'яті й перебирати їх на кожен запит.
Але за це доводиться платити. На відкладених 240 оголошеннях гаусів Баєс дає точність 0.871, а kNN із дев'ятьма сусідами — 0.917 (тривіальна відповідь «усі чесні» дає 0.733). Причину видно з таблиці вище: шахрайство на нашій дошці двох ґатунків — дешеві приманки й вузький «преміум»-згусток біля ринкової ціни. Це два горби по осі ціни, а гаусів Баєс має право намалювати в класі лише один: він розтягує єдиний дзвін між обома згустками й неминуче мажe. kNN, який нічого не припускає про форму, обводить обидві області окремо.
08 / МежіКоли він доречний
Тепер, коли метод розібраний до гвинтика, можна сказати, де його місце.
Швидкість. Навчання — це один прохід по даних із лічильниками. Ані градієнтного спуску, ані підбору кроку, ані збіжності: мільйон листів обробляється за секунди, а модель займає стільки пам'яті, скільки в ній чисел. Дописати новий приклад теж дешево — досить збільшити кілька лічильників.
Текст. Тут наївний Баєс почувається найкраще: слів багато, кожне окремо слабке, разом вони дають сильний сигнал — саме та ситуація, для якої добуток правдоподібностей і придуманий. Перші фільтри спаму були такими й працювали добре, поки спамери не навчились розбавляти листи нормальним текстом, щоб зсунути частоти.
Базова лінія. Найкорисніша роль методу сьогодні. Перш ніж будувати щось складне, запусти наївний Баєс: п'ять рядків коду дають число, з яким можна порівнювати все інше. Якщо важка модель ледве обганяє наївного Баєса — це сигнал не про модель, а про дані. Він же виграє на маленьких вибірках: параметрів мало, оцінювати їх легко. Зворотний бік — з великою вибіркою він майже не покращується, бо впирається у власне припущення.
Слабкі місця, і всі вони випливають із наївності:
- Сильно залежні ознаки. Продублюй колонку — і наївний Баєс порахує це свідчення двічі, ставши вдвічі впевненішим без жодної нової інформації. Логістична регресія в тій самій ситуації поділить коефіцієнт навпіл.
- Взаємодії ознак. Ситуацію «низька ціна погана лише в парі зі свіжим акаунтом» модель не бачить принципово: вона підсумовує внески ознак окремо й не має де записати їхню взаємодію.
- Зсув класів. Апріорні ймовірності беруться з навчальної вибірки,
тож на бойових даних з іншою часткою шахраїв вирок буде зміщений. Виправляється
аргументом
priorsабоclass_prior.
09 / ПідсумокЩо варто винести
Дві теми поспіль ми розв'язували одну задачу протилежними способами. kNN зберігає весь архів і не узагальнює нічого — відкладає всю роботу до моменту запиту. Наївний Баєс проходить по архіву один раз, згортає його до жменьки ймовірностей і викидає таблицю. Перший дорого відповідає, другий дорого припускає.
| ідея | суть | чому важливо |
|---|---|---|
| розворот | P(A|B) не дорівнює P(B|A) | рахуємо одне, а потрібне інше |
| теорема Баєса | множимо на апріорну, ділимо на ймовірність свідчення | чесний спосіб перевернути питання |
| апріорна | частка класу до будь-яких свідчень | при рідкісному класі більшість спрацювань хибні |
| наївність | ознаки вважаються незалежними | припущення хибне, метод усе одно працює |
| вирок | порівняння двох добутків | важливий порядок, а не самі числа |
| Лаплас | додати α до кожного лічильника | без цього одне слово накладає вето |
| логарифми | добуток стає сумою | без цього довгий текст дає машинний нуль |
| різновиди | частоти, дзвони або прапорці | обирається за типом ознаки |
Тут закінчується блок про класичні моделі. Ти вже маєш кілька різних відповідей на одну
задачу — логістичну регресію,
kNN, наївного Баєса, попереду
дерева рішень — і жодна з них не
«найкраща». Тому наступний блок про інше: як зрозуміти, якій із них вірити.
Перше питання там — перенавчання: чому модель, яка ідеально відповідає
на навчальні дані, буває нікчемною на нових. Ти вже бачив це двічі: kNN при
k = 1 запам'ятовував кожну випадковість архіву, а наївний Баєс без
згладжування робив абсолютний висновок з одного невидимого слова. Далі це розкладається
на зміщення й дисперсію — тема
Bias-Variance, — а чесно міряти обидва
навчить крос-валідація.
І остання думка, ширша за метод. Наївний Баєс — найпростіший приклад ймовірнісного погляду на машинне навчання: модель не малює межу, а описує, як улаштований кожен клас, і питає, з якого з них імовірніше походить об'єкт. Той самий хід — оцінити правдоподібність і зважити її на апріорну — лежить в основі куди складніших речей. Розворот, з якого ми почали, вартий того, щоб пам'ятати його довше за формулу.
practice.ipynb ти збереш той
самий архів зі ста оголошень, порахуєш усі ймовірності руками на NumPy й переконаєшся,
що MultinomialNB дає ті самі числа. Потім вимкнеш згладжування, перейдеш
на логарифми — і порівняєш GaussianNB із kNN на числових ознаках.Далі в темі
Теорію прочитано. Тепер закріпи її на практиці.