Naive Bayes 📧
Открой почтовый ящик и посмотри в папку «Спам». Каждое письмо там оказалось не потому, что кто-то вручную прочитал его и вынес вердикт, а потому, что алгоритм за доли секунды посчитал: слово «выигрыш» встречается в спаме намного чаще, чем в обычной переписке, слово «встреча» — наоборот, три восклицательных знака подряд — тревожный сигнал, а адрес отправителя из незнакомого домена добавляет подозрений. Модель перемножила эти «кусочки улик» и получила число — вероятность того, что письмо мусорное. Этот алгоритм называется наивный байесовский классификатор, по-английски Naive Bayes, и он остаётся одним из самых надёжных рабочих инструментов классификации текста спустя почти три десятилетия после того, как индустрия начала его массово использовать.
В прошлом уроке ты разобрался с методом k ближайших соседей — алгоритмом, который классифицирует объект по голосованию похожих соседей, ничего заранее не «выучивая», а просто запоминая всю обучающую выборку. Наивный байесовский классификатор устроен принципиально иначе: он строит явную вероятностную модель данных, заранее подсчитывая, как часто те или иные признаки встречаются в каждом классе, а затем применяет эти подсчитанные вероятности к новому объекту. Для этого ему не нужно хранить всю обучающую выборку и не нужно ничего перебирать во время предсказания — только один проход по обучающим данным, чтобы посчитать частоты, и одно умножение вероятностей, чтобы классифицировать новый объект.
Название «наивный» звучит как недостаток, и в каком-то смысле это действительно так: алгоритм предполагает, что все признаки объекта условно независимы друг от друга при заданном классе — что появление слова «деньги» в письме никак не связано с появлением слова «выигрыш» в том же письме, если мы уже знаем, что письмо спам. В реальных текстах это, конечно, не так: слова в естественном языке связаны друг с другом грамматикой, темой, стилем автора. И тем не менее, невзирая на эту откровенно нарушенную предпосылку, наивный Байес десятилетиями остаётся рабочей лошадкой прикладной классификации текстов — от спам-фильтров и анализа тональности отзывов до медицинской диагностики по набору симптомов. Разобраться, почему заведомо неверное предположение всё равно приводит к рабочему алгоритму, и есть главная интеллектуальная задача этого урока.
К концу урока ты сможешь не просто процитировать формулу теоремы Байеса, а провести полный численный расчёт: по частотам слов в обучающей выборке письмо определённо отнести к спаму или не к спаму, объяснить, почему без сглаживания Лапласа один невиданный алгоритмом термин может обнулить всю вероятность класса, и осознанно выбрать между GaussianNB, MultinomialNB и BernoulliNB в зависимости от типа признаков в твоей задаче.
🎯 Ты узнаешь:
- Как теорема Байеса переворачивает вопрос «какова вероятность причины при данных следствиях» и как из неё выводится классификатор, максимизирующий апостериорную вероятность класса
- В чём именно состоит «наивное» предположение об условной независимости признаков и почему нарушение этого предположения на практике редко ломает итоговую классификацию
- Чем отличаются друг от друга гауссовский, мультиномиальный и бернуллиевский варианты наивного Байеса и для какого типа признаков подходит каждый из них
- Как работает сглаживание Лапласа и почему без него один невиданный признак может обнулить вероятность целого класса
- Как провести полный численный расчёт классификации спам-письма по частотам слов — тот самый вычислительный конвейер, что стоит за
sklearn.naive_bayes.MultinomialNB - Как наивный Байес связан с теоремой Байеса из теории вероятностей и с методом максимального правдоподобия, на котором строится обучение почти всех параметрических моделей
История: от задачи о шаре на столе до спам-фильтра
Английский пресвитерианский священник и математик-любитель Томас Байес родился около 1701 года и при жизни не опубликовал теорему, которая позже станет носить его имя. Байес интересовался задачами теории вероятностей в свободное от церковных обязанностей время и оставил после смерти в 1761 году неопубликованную рукопись под названием «Опыт решения одной задачи в учении о шансах» (An Essay towards solving a Problem in the Doctrine of Chances). В этой работе он предложил способ пересчитывать вероятность причины по наблюдаемым следствиям — по сути, впервые сформулировал идею, которую сегодня называют байесовским выводом. Рукопись обнаружил и подготовил к публикации друг Байеса, математик Ричард Прайс, который в 1763 году представил её Королевскому обществу и опубликовал в трудах общества уже после смерти автора. Сам Байес, вероятно, даже не подозревал, что его имя переживёт века и станет ассоциироваться с одним из самых универсальных принципов статистики.
Следующие два столетия теорема Байеса развивалась в основном в академической статистике, а её массовое прикладное применение началось только с приходом эпохи электронной почты и первых потоков нежелательной рекламной рассылки. В середине и конце 1990-х годов исследователи начали формально применять байесовский подход к фильтрации спама — в частности, статья Мехрана Сахами и соавторов 1998 года «A Bayesian Approach to Filtering Junk E-Mail» одной из первых показала, что классификатор, перемножающий вероятности отдельных слов, работает на удивление хорошо. По-настоящему массовую популярность идея получила в 2002 году, когда программист и предприниматель Пол Грэм опубликовал эссе «A Plan for Spam», в котором показал, что простой наивный байесовский фильтр, обученный на личной переписке пользователя, справляется со спамом заметно лучше, чем ручные списки правил и чёрные списки отправителей, которыми до этого пользовалось большинство почтовых клиентов.
Эссе Грэма запустило волну практических реализаций: на его идеях выросли ранние версии открытых фильтров вроде SpamAssassin и SpamBayes, а крупные почтовые сервисы, включая Gmail, в первые годы своего существования опирались на байесовские и родственные им вероятностные модели как на один из ключевых компонентов защиты от спама (сегодня к ним добавились куда более сложные модели, но байесовский принцип частотного анализа слов остаётся частью многоуровневой защиты). Ирония в том, что метод, придуманный священником XVIII века для рассуждений о шансах, оказался идеально приспособлен именно к задаче, которую невозможно было даже представить при жизни автора, — отделять полезные письма от рекламного мусора в электронном почтовом ящике.
Теорема Байеса: от условной вероятности к классификатору
Интуиция
Представь, что ты не автор письма, а детектив, который получил письмо и должен решить: спам это или нет. Прямой вопрос — «какова вероятность, что это письмо спам» — сформулировать сложно, потому что тебе неизвестно ничего, кроме самого текста письма. Но перевёрнутый вопрос сформулировать значительно проще: «если бы я знал, что письмо — спам, какова была бы вероятность встретить в нём именно такие слова?» На это ответить легко: достаточно взять большую коллекцию уже размеченных спам-писем и посчитать, как часто в них встречается каждое слово.
Именно это и делает теорема Байеса — она даёт формальный мост между «вероятностью следствия при известной причине» (которую легко оценить по обучающим данным) и «вероятностью причины при известном следствии» (которую нужно найти для классификации). Причина в нашем случае — это класс письма (спам или не спам), а следствие — это набор слов, которые мы в этом письме наблюдаем.
Определение (теорема Байеса и байесовский классификатор). Пусть $c$ — метка класса (например, «спам» или «не спам»), а $x_1,\dots,x_n$ — значения признаков объекта (например, слова в письме). Теорема Байеса связывает апостериорную вероятность класса при известных признаках с обратной, легко оцениваемой по данным величиной:
$$P(c \mid x_1,\dots,x_n) = \frac{P(x_1,\dots,x_n \mid c)\cdot P(c)}{P(x_1,\dots,x_n)}.$$Здесь $P(c)$ — априорная вероятность класса (доля класса в обучающей выборке, известная ещё до того, как мы увидели признаки), $P(x_1,\dots,x_n\mid c)$ — правдоподобие признаков при данном классе, а $P(x_1,\dots,x_n)$ — вероятность самих признаков, не зависящая от того, какой класс мы рассматриваем.
Классификатор выбирает класс, максимизирующий апостериорную вероятность:
$$\hat c = \arg\max_{c} P(c \mid x_1,\dots,x_n).$$Поскольку знаменатель $P(x_1,\dots,x_n)$ одинаков для всех классов и не влияет на то, какой класс даёт максимум, его можно отбросить и сравнивать только числитель:
$$\hat c = \arg\max_{c} \; P(x_1,\dots,x_n \mid c)\cdot P(c).$$
Это ключевой ход: чтобы найти самый вероятный класс, вовсе не обязательно вычислять точную вероятность $P(c\mid x)$ — достаточно вычислить для каждого класса величину, пропорциональную ей, и сравнить эти величины между собой. Тот класс, у которого произведение $P(x\mid c)\cdot P(c)$ больше, и объявляется победителем.
Примеры с разбором
Пример 1 (лёгкий). Редкое заболевание встречается у 1% населения. Диагностический тест верно обнаруживает болезнь у 95% больных (то есть $P(\text{тест}{+}\mid \text{болен})=0{,}95$) и верно даёт отрицательный результат у 95% здоровых (то есть вероятность ложноположительного результата $P(\text{тест}{+}\mid \text{здоров})=0{,}05$). Пациент получил положительный результат. Какова вероятность, что он действительно болен?
Обозначим $A$ — событие «болен», $B$ — событие «тест положительный». По теореме Байеса:
$$P(A\mid B) = \frac{P(B\mid A)\cdot P(A)}{P(B)}.$$Сначала нужно найти полную вероятность положительного теста $P(B)$ — она складывается из истинноположительных и ложноположительных случаев:
$$P(B) = P(B\mid A)\cdot P(A) + P(B\mid \neg A)\cdot P(\neg A) = 0{,}95\cdot0{,}01 + 0{,}05\cdot0{,}99 = 0{,}0095+0{,}0495 = 0{,}059.$$Теперь подставляем в формулу Байеса:
$$P(A\mid B) = \frac{0{,}95\cdot0{,}01}{0{,}059} = \frac{0{,}0095}{0{,}059} \approx 0{,}161.$$Ответ: вероятность того, что пациент действительно болен, составляет лишь около $16{,}1\%$, несмотря на положительный результат «95%-точного» теста. Этот пример — классическая иллюстрация того, почему низкая априорная вероятность (редкая болезнь) резко снижает доверие даже к достаточно точному тесту: подавляющее большинство положительных результатов при редком заболевании — это ложные тревоги среди огромной массы здоровых людей.
Пример 2 (средний). У тебя есть письмо, содержащее слово «скидка». Известно: $P(\text{спам})=0{,}4$, $P(\text{не спам})=0{,}6$, $P(\text{«скидка»}\mid\text{спам})=0{,}6$, $P(\text{«скидка»}\mid\text{не спам})=0{,}1$. Вычисли непронормированные оценки для обоих классов и определи, какой класс выбирает классификатор.
По формуле байесовского классификатора для каждого класса считаем произведение $P(x\mid c)\cdot P(c)$:
$$\text{Score(спам)} = P(\text{«скидка»}\mid\text{спам})\cdot P(\text{спам}) = 0{,}6\cdot0{,}4 = 0{,}24,$$$$\text{Score(не спам)} = P(\text{«скидка»}\mid\text{не спам})\cdot P(\text{не спам}) = 0{,}1\cdot0{,}6 = 0{,}06.$$
Чтобы получить настоящую вероятность (не просто пропорциональную величину), нормируем — делим каждую оценку на их сумму:
$$P(\text{спам}\mid x) = \frac{0{,}24}{0{,}24+0{,}06} = \frac{0{,}24}{0{,}30} = 0{,}8.$$Ответ: классификатор выбирает класс «спам» с апостериорной вероятностью $80\%$. Обрати внимание: нормировка не изменила порядок классов (спам всё равно побеждает), она лишь превратила пропорциональные величины в настоящие вероятности, суммирующиеся к единице — для самой классификации нормировка не обязательна, но она нужна, если тебе важно знать степень уверенности модели.
Пример 3 (сложный, полный расчёт по частотам слов). Есть обучающая выборка из десяти писем: четыре спам-письма и шесть обычных. В спам-письмах в сумме 40 слов, из них слово «деньги» встретилось 8 раз, «скидка» — 10 раз, «бесплатно» — 6 раз. В обычных письмах в сумме 60 слов, из них «деньги» встретилось 3 раза, «скидка» — 4 раза, «бесплатно» — 1 раз. Новое письмо содержит слова «деньги скидка бесплатно». К какому классу его отнести?
Шаг 1. Считаем априорные вероятности классов по доле писем каждого класса в обучающей выборке:
$$P(\text{спам}) = \frac{4}{10} = 0{,}4, \qquad P(\text{не спам}) = \frac{6}{10} = 0{,}6.$$Шаг 2. Считаем условные вероятности каждого слова внутри своего класса как долю его вхождений среди всех слов класса (это оценка методом максимального правдоподобия для мультиномиального распределения — ты уже встречал этот принцип в уроке 246 про оценку параметров):
$$P(\text{«деньги»}\mid\text{спам}) = \frac{8}{40}=0{,}2, \quad P(\text{«скидка»}\mid\text{спам}) = \frac{10}{40}=0{,}25, \quad P(\text{«бесплатно»}\mid\text{спам}) = \frac{6}{40}=0{,}15,$$$$P(\text{«деньги»}\mid\text{не спам}) = \frac{3}{60}\approx0{,}05, \quad P(\text{«скидка»}\mid\text{не спам}) = \frac{4}{60}\approx0{,}0667, \quad P(\text{«бесплатно»}\mid\text{не спам}) = \frac{1}{60}\approx0{,}0167.$$
Шаг 3. В силу наивного предположения о независимости (о нём подробно — в следующем разделе) перемножаем условные вероятности всех слов внутри класса и умножаем на априорную вероятность класса:
$$\text{Score(спам)} = 0{,}4 \cdot 0{,}2 \cdot 0{,}25 \cdot 0{,}15 = 0{,}003,$$$$\text{Score(не спам)} = 0{,}6 \cdot 0{,}05 \cdot 0{,}0667 \cdot 0{,}0167 \approx 0{,}0000333.$$
Шаг 4. Нормируем, чтобы получить настоящую вероятность:
$$P(\text{спам}\mid x) = \frac{0{,}003}{0{,}003+0{,}0000333} \approx 0{,}989.$$Ответ: письмо классифицируется как спам с вероятностью около $98{,}9\%$. Обрати внимание на масштаб разницы между оценками: $0{,}003$ против $0{,}0000333$ — почти в 90 раз. Именно такая резкая, почти категоричная разница в итоговых оценках типична для текстовой классификации, где даже несколько характерных слов дают очень уверенный вердикт.
Почему это важно. Весь конвейер, который ты только что прошёл вручную — подсчёт частот по обучающей выборке, перемножение условных вероятностей, сравнение итоговых оценок между классами, — это буквально то, что делает sklearn.naive_bayes.MultinomialNB при вызове .fit() и .predict(), только на словаре из десятков тысяч слов и миллионах писем вместо трёх слов и десяти писем. Понимание этого расчёта на бумаге — это понимание того, что происходит внутри одного из самых массово используемых инструментов классификации текста.
Наивное предположение независимости: почему оно «наивное» и почему всё равно работает
Интуиция
В примере выше мы без объяснений перемножили $P(\text{«деньги»}\mid c)$, $P(\text{«скидка»}\mid c)$ и $P(\text{«бесплатно»}\mid c)$, как будто эти три вероятности никак не связаны друг с другом. На самом деле точная формула требует совсем другого — вероятности совместного появления всех слов сразу, $P(\text{«деньги», «скидка», «бесплатно»}\mid c)$, а это, вообще говоря, не равно произведению отдельных вероятностей, если слова коррелируют друг с другом внутри письма (а в естественном языке они почти всегда коррелируют: если в письме есть «скидка», то с повышенной вероятностью рядом окажется и «акция», и «только сегодня»).
Проблема в том, что оценить точную совместную вероятность по обучающей выборке практически невозможно: для словаря даже из тысячи слов число возможных комбинаций их присутствия и отсутствия астрономически велико, и почти ни одна конкретная комбинация не встретится в обучающих данных достаточно много раз, чтобы надёжно оценить её вероятность. Наивный Байес обходит эту проблему радикально — он просто предполагает, что все признаки условно независимы друг от друга при известном классе, и раскладывает совместную вероятность в произведение вероятностей по отдельности.
Определение (наивное предположение и итоговая формула классификатора). Наивное предположение состоит в том, что при фиксированном классе $c$ признаки $x_1,\dots,x_n$ условно независимы друг от друга:
$$P(x_1,x_2,\dots,x_n \mid c) = P(x_1\mid c)\cdot P(x_2\mid c)\cdots P(x_n\mid c) = \prod_{i=1}^n P(x_i\mid c).$$Подставляя это разложение в формулу байесовского классификатора из предыдущего раздела, получаем итоговую рабочую формулу наивного Байеса:
$$\hat c = \arg\max_{c}\; P(c)\prod_{i=1}^n P(x_i\mid c).$$Именно за это допущение — что признак «деньги» никак не влияет на вероятность признака «скидка» при известном классе, хотя в реальности они, конечно, связаны, — алгоритм и получил в названии слово «наивный».
Примеры с разбором
Пример 1 (лёгкий). Без наивного допущения для трёх бинарных признаков (есть слово / нет слова) нужно было бы оценить полную совместную вероятность — таблицу из $2^3=8$ возможных комбинаций присутствия слов для каждого класса. Наивное допущение вместо этого требует оценить всего 3 отдельные вероятности на класс. Оцени, во сколько раз меньше параметров нужно оценивать наивной моделью, если признаков не 3, а 20 (все бинарные).
Без допущения независимости число комбинаций (а значит, и параметров совместного распределения) растёт как $2^{20} = 1\,048\,576$. С наивным допущением нужно оценить всего 20 отдельных вероятностей на класс — по одной на признак.
Ответ: наивное предположение сокращает число оцениваемых параметров с более чем миллиона до двадцати — сокращение более чем в 50 000 раз. Это не просто удобство: без такого сокращения совместную вероятность физически невозможно было бы надёжно оценить ни по какой реалистичной по размеру обучающей выборке, потому что подавляющее большинство из миллиона возможных комбинаций признаков никогда не встретится в обучающих данных ни разу.
Пример 2 (средний). Пусть в реальности признаки «деньги» и «скидка» сильно коррелируют внутри спам-писем (если есть одно, почти наверняка есть и другое), так что истинная совместная вероятность $P(\text{«деньги», «скидка»}\mid\text{спам}) = 0{,}22$, тогда как наивное произведение отдельных вероятностей даёт $P(\text{«деньги»}\mid\text{спам})\cdot P(\text{«скидка»}\mid\text{спам}) = 0{,}2\cdot0{,}25=0{,}05$. Если для класса «не спам» аналогично истинная совместная вероятность равна $0{,}006$, а наивное произведение даёт $0{,}05\cdot0{,}0667\approx0{,}0033$, сравни, к какому классу приводит точный расчёт и к какому — наивное приближение (приоры $P(\text{спам})=0{,}4$, $P(\text{не спам})=0{,}6$ те же, что раньше).
Точный расчёт: $\text{Score}_{\text{точн}}(\text{спам}) = 0{,}4\cdot0{,}22=0{,}088$; $\text{Score}_{\text{точн}}(\text{не спам})=0{,}6\cdot0{,}006=0{,}0036$. Отношение оценок $0{,}088/0{,}0036\approx24{,}4$ в пользу спама.
Наивный расчёт: $\text{Score}_{\text{наив}}(\text{спам})=0{,}4\cdot0{,}05=0{,}02$; $\text{Score}_{\text{наив}}(\text{не спам})=0{,}6\cdot0{,}0033\approx0{,}00198$. Отношение оценок $0{,}02/0{,}00198\approx10{,}1$ в пользу спама.
Ответ: абсолютные числа сильно разошлись (наивное приближение занизило и оценку спама, и оценку не спама, потому что проигнорировало положительную корреляцию признаков внутри спам-писем), но оба расчёта единогласно выбирают класс «спам» — просто с разной степенью «уверенности» в отношении оценок ($24{,}4$ против $10{,}1$). Это и есть ключевое наблюдение: наивное предположение искажает абсолютные значения вероятностей, но для итоговой классификации важен не абсолютный уровень вероятности, а то, какой класс получает бо́льшую оценку — а порядок сравнения часто сохраняется даже при заметном искажении масштаба.
Пример 3 (сложный). Объясни, почему для двух классов с сильно различающимися профилями признаков (например, «спам» и «не спам» отличаются по большинству характерных слов) наивное допущение обычно не меняет итоговое решение классификатора, а для двух классов с очень похожими профилями признаков ошибка от нарушения независимости может стать критичной.
Когда классы сильно различаются по своим типичным признакам, разница в произведениях условных вероятностей между классами настолько велика (как в примере 3 предыдущего раздела — разница почти в 90 раз), что даже заметное искажение масштаба из-за игнорирования корреляций не способно «перевернуть» сравнение — большая оценка остаётся большей, даже если её абсолютное значение пересчитано неточно. Когда же классы похожи (например, различить схожие категории новостных статей о смежных темах), итоговые оценки $\text{Score}(c_1)$ и $\text{Score}(c_2)$ изначально близки друг к другу, и тогда даже небольшое искажение от нарушенной независимости признаков способно поменять их порядок и привести к неверной классификации.
Ответ: наивное предположение «прощается» алгоритму тем сильнее, чем более разделимы классы по своим характерным признакам, и становится проблематичным именно на пограничных, трудноразличимых случаях — там, где любая неточность в оценке вероятностей может определить исход классификации.
Почему это важно. Это наблюдение объясняет знаменитый факт, впервые формально исследованный в статье Педро Домингоса и Майкла Пазцани «On the Optimality of the Simple Bayesian Classifier under Zero-One Loss» (1997): наивный Байес часто даёт корректную классификацию даже тогда, когда его вероятностные оценки откровенно неточные, потому что для задачи классификации (в отличие от задачи точной оценки вероятности) важен не абсолютный уровень $P(c\mid x)$, а только то, какой класс получает наибольшее значение. Отсюда практический вывод: не доверяй абсолютным числам, которые наивный Байес выдаёт как «вероятность класса» (predict_proba в sklearn часто даёт переоценённые, близкие к 0 или 1 значения), но доверяй самому факту, какой класс он выбрал как более вероятный.
Варианты наивного Байеса: гауссовский, мультиномиальный, бернуллиевский
Интуиция
Формула $P(c)\prod_i P(x_i\mid c)$ универсальна, но то, как именно считать каждую отдельную вероятность $P(x_i\mid c)$, зависит от типа признака. Если признак — это непрерывное число (рост человека, температура тела, цена товара), нельзя посчитать «долю вхождений» — нужно предположить какое-то распределение внутри класса и оценить его параметры. Если признак — это счётчик, сколько раз слово встретилось в документе, нужна модель, оперирующая частотами. А если признак — это просто бинарный факт «есть слово в документе или нет», не важно, сколько раз, — нужна ещё одна, третья модель. Из этих трёх типовых ситуаций и выросли три классических варианта наивного Байеса.
Определение (три варианта наивного Байеса).
Гауссовский наивный Байес (Gaussian Naive Bayes,
$$P(x_i \mid c) = \frac{1}{\sqrt{2\pi\sigma^2_{c,i}}}\exp\left(-\frac{(x_i-\mu_{c,i})^2}{2\sigma^2_{c,i}}\right).$$GaussianNB) — для непрерывных признаков. Внутри каждого класса $c$ признак $x_i$ предполагается нормально распределённым со своими средним $\mu_{c,i}$ и дисперсией $\sigma^2_{c,i}$, оцениваемыми по обучающей выборке:Мультиномиальный наивный Байес (Multinomial Naive Bayes,
MultinomialNB) — для счётных признаков, прежде всего для частот слов в тексте. Если $x_i$ — это число вхождений признака (слова) в документ, а $P(w\mid c)$ — вероятность этого слова в классе, оценённая как доля его вхождений среди всех слов класса, то вклад признака в правдоподобие документа пропорционален $P(w\mid c)^{x_i}$ — именно эта модель стоит за расчётом из первого раздела урока.Бернуллиевский наивный Байес (Bernoulli Naive Bayes,
$$P(x_i\mid c) = p_{c,i}^{\,x_i}\cdot(1-p_{c,i})^{\,1-x_i}.$$BernoulliNB) — для бинарных признаков «есть/нет», без учёта количества повторений. Для признака $x_i\in\{0,1\}$ (слово присутствует в документе или отсутствует) с параметром $p_{c,i}=P(x_i=1\mid c)$:Ключевое отличие от мультиномиального варианта: бернуллиевская модель явно штрафует за отсутствие ожидаемого слова через множитель $(1-p_{c,i})$, тогда как мультиномиальная модель просто игнорирует слова, которых нет в документе.
Примеры с разбором
Пример 1 (гауссовский вариант, лёгкий-средний). Классифицируем фрукты по весу. В обучающей выборке веса яблок — 150, 170, 160, 180 граммов, веса апельсинов — 190, 200, 210, 220 граммов. Приоры $P(\text{яблоко})=0{,}6$, $P(\text{апельсин})=0{,}4$. Новый фрукт весит 175 граммов. К какому классу его отнести?
Шаг 1. Считаем среднее и дисперсию веса для каждого класса. Для яблок: среднее $\mu_{\text{ябл}} = (150+170+160+180)/4=165$; отклонения от среднего — $-15,5,-5,15$, их квадраты — $225,25,25,225$, сумма $=500$, дисперсия $\sigma^2_{\text{ябл}}=500/4=125$. Для апельсинов аналогично получается $\mu_{\text{апельс}}=205$, $\sigma^2_{\text{апельс}}=125$ (та же дисперсия — данные подобраны симметрично для наглядности).
Шаг 2. Считаем плотность нормального распределения для $x=175$ в каждом классе:
$$f_{\text{ябл}}(175) = \frac{1}{\sqrt{2\pi\cdot125}}\exp\left(-\frac{(175-165)^2}{2\cdot125}\right) = 0{,}0357\cdot\exp(-0{,}4)\approx0{,}0357\cdot0{,}6703\approx0{,}0239,$$$$f_{\text{апельс}}(175) = \frac{1}{\sqrt{2\pi\cdot125}}\exp\left(-\frac{(175-205)^2}{2\cdot125}\right) = 0{,}0357\cdot\exp(-3{,}6)\approx0{,}0357\cdot0{,}0273\approx0{,}000975.$$
Шаг 3. Умножаем на приоры и нормируем:
$$\text{Score(яблоко)} = 0{,}6\cdot0{,}0239 \approx 0{,}01435, \qquad \text{Score(апельсин)} = 0{,}4\cdot0{,}000975\approx0{,}00039,$$$$P(\text{яблоко}\mid x=175) = \frac{0{,}01435}{0{,}01435+0{,}00039}\approx0{,}974.$$
Ответ: фрукт весом 175 граммов классифицируется как яблоко с вероятностью около $97{,}4\%$ — вес значительно ближе к среднему весу яблок (165 г), чем к среднему весу апельсинов (205 г), и гауссовская плотность резко убывает по мере удаления от среднего значения класса.
Пример 2 (мультиномиальный вариант, средний). Классификатор тональности отзывов знает: $P(\text{«отлично»}\mid\text{позитив})=0{,}15$, $P(\text{«плохо»}\mid\text{позитив})=0{,}02$, $P(\text{«отлично»}\mid\text{негатив})=0{,}03$, $P(\text{«плохо»}\mid\text{негатив})=0{,}18$. Приоры классов равны ($0{,}5$ и $0{,}5$). Отзыв содержит слово «отлично» дважды и слово «плохо» один раз. Определи тональность.
В мультиномиальной модели каждое слово вносит вклад в правдоподобие в степени, равной числу его вхождений:
$$\text{Score(позитив)} = 0{,}5\cdot(0{,}15)^2\cdot(0{,}02)^1 = 0{,}5\cdot0{,}0225\cdot0{,}02=0{,}000225,$$$$\text{Score(негатив)} = 0{,}5\cdot(0{,}03)^2\cdot(0{,}18)^1 = 0{,}5\cdot0{,}0009\cdot0{,}18=0{,}000081.$$
Нормируем: $P(\text{позитив}\mid x) = 0{,}000225/(0{,}000225+0{,}000081) \approx 0{,}735$.
Ответ: отзыв классифицируется как позитивный с вероятностью около $73{,}5\%$ — повторное появление слова «отлично» (в степени 2) перевешивает единичное появление слова «плохо», несмотря на то что «плохо» само по себе намного сильнее указывает на негатив, чем «отлично» на позитив. Это ровно тот механизм, который использует MultinomialNB при вызове .fit(X_counts, y) на матрице частот слов, построенной, например, CountVectorizer из sklearn: он подсчитывает частоты слов в каждом классе на обучающей выборке и на предсказании умножает вероятности слов в степенях, равных их числу вхождений в новый документ.
Пример 3 (бернуллиевский вариант, средний-сложный). Классификатор спама смотрит не на частоты, а на присутствие слов. Среди 4 спам-писем слово «деньги» присутствует в 3 из них, «скидка» — в 2, «привет» — в 1. Среди 6 обычных писем «деньги» присутствует в 1, «скидка» — в 1, «привет» — в 5. Приоры $P(\text{спам})=0{,}4$, $P(\text{не спам})=0{,}6$. Новое письмо содержит слово «деньги», но не содержит ни «скидка», ни «привет». Классифицируй его.
Шаг 1. Оцениваем параметры $p_{c,i}=P(x_i=1\mid c)$ как долю писем класса, где слово присутствует:
$$p_{\text{деньги, спам}}=\tfrac34=0{,}75,\ p_{\text{скидка, спам}}=\tfrac24=0{,}5,\ p_{\text{привет, спам}}=\tfrac14=0{,}25,$$$$p_{\text{деньги, не спам}}=\tfrac16\approx0{,}167,\ p_{\text{скидка, не спам}}=\tfrac16\approx0{,}167,\ p_{\text{привет, не спам}}=\tfrac56\approx0{,}833.$$
Шаг 2. Новое письмо описывается вектором присутствия $[1, 0, 0]$ (деньги — есть, скидка — нет, привет — нет). В бернуллиевской модели для отсутствующих признаков используется множитель $(1-p)$:
$$P(x\mid\text{спам}) = p_{\text{деньги,спам}}\cdot(1-p_{\text{скидка,спам}})\cdot(1-p_{\text{привет,спам}}) = 0{,}75\cdot0{,}5\cdot0{,}75 = 0{,}28125,$$$$P(x\mid\text{не спам}) = p_{\text{деньги,неспам}}\cdot(1-p_{\text{скидка,неспам}})\cdot(1-p_{\text{привет,неспам}}) = 0{,}167\cdot0{,}833\cdot0{,}167 \approx 0{,}02315.$$
Шаг 3. Умножаем на приоры и нормируем:
$$\text{Score(спам)}=0{,}4\cdot0{,}28125=0{,}1125, \qquad \text{Score(не спам)}=0{,}6\cdot0{,}02315\approx0{,}01389,$$$$P(\text{спам}\mid x) = \frac{0{,}1125}{0{,}1125+0{,}01389}\approx0{,}890.$$
Ответ: письмо классифицируется как спам с вероятностью около $89\%$. Обрати внимание на роль отсутствия слова «привет»: оно встречается в $5$ из $6$ обычных писем, поэтому его отсутствие в новом письме — это сильный аргумент против класса «не спам» (множитель $1-0{,}833=0{,}167$ заметно понижает оценку этого класса). Мультиномиальная модель этот сигнал бы полностью проигнорировала, потому что она учитывает только слова, которые реально есть в документе, — и это главное практическое отличие двух моделей.
Почему это важно. Выбор варианта наивного Байеса — это не формальность, а решение, которое напрямую определяет качество модели. Подать непрерывные признаки в MultinomialNB или бинарные признаки в GaussianNB без осмысленного преобразования — типичная ошибка новичка, которая незаметно портит качество классификации, даже если код не выдаёт никакой ошибки: библиотека просто посчитает не те статистики, которые нужны для данных такого типа, и результат окажется хуже, чем мог бы быть. Именно поэтому sklearn.naive_bayes.MultinomialNB — стандартный инструмент базовой классификации текста (спам-фильтры, анализ тональности отзывов) в промышленных пайплайнах: он идеально подходит под естественный формат текстовых данных — матрицу частот или TF-IDF-весов слов, — обучается практически мгновенно (без единого шага итеративной оптимизации, только подсчёт частот) и на разреженных, высокоразмерных текстовых признаках нередко даёт качество, сравнимое с куда более тяжёлыми моделями.
Сглаживание Лапласа: как побороть нулевую вероятность
Интуиция
Вернись к примеру с классификацией по частотам слов. Что произойдёт, если в новом письме встретится слово, которого не было ни разу ни в одном обучающем письме класса «не спам»? Оценка этого слова получится $P(w\mid\text{не спам}) = 0/60 = 0$. А поскольку итоговая оценка класса — это произведение вероятностей всех слов, умножение на ноль обнулит весь результат целиком, вне зависимости от того, насколько убедительны остальные слова в пользу этого класса. Один невиданный термин перечёркивает всю накопленную статистику — очевидно нежелательное поведение: отсутствие данных о слове не должно означать «это слово абсолютно невозможно встретить в этом классе», это означает лишь «в обучающей выборке нам не повезло его не увидеть».
Решение предложил ещё Пьер-Симон Лаплас в XVIII веке, размышляя над похожей по духу «задачей о восходе солнца»: как оценить вероятность события, если оно наблюдалось много раз подряд успешно, но нельзя с абсолютной уверенностью утверждать, что оно невозможно провалится. Идея сглаживания Лапласа (add-one smoothing) в том, чтобы добавить к каждому счётчику небольшую условную «добавку» — как будто каждое слово словаря уже виделось хотя бы один раз в каждом классе, даже если на самом деле оно не встретилось ни разу.
Определение (сглаживание Лапласа). Пусть $\text{count}(w,c)$ — число вхождений слова $w$ в обучающих документах класса $c$, $\text{count}(c)$ — суммарное число слов во всех документах класса $c$, а $|V|$ — размер словаря (число уникальных слов во всей обучающей выборке). Сглаженная (аддитивная) оценка вероятности слова:
$$P(w\mid c) = \frac{\text{count}(w,c) + \alpha}{\text{count}(c) + \alpha\cdot|V|}.$$При $\alpha=1$ это классическое сглаживание Лапласа (add-one smoothing): к числителю каждого слова прибавляется единица, а к знаменателю — размер словаря, чтобы итоговые вероятности всех слов класса по-прежнему в сумме давали единицу. Параметр $\alpha$ можно уменьшать (слабее сглаживание, ближе к «сырым» частотам) или увеличивать (сильнее сглаживание, вероятности внутри класса выравниваются); в
sklearn.naive_bayes.MultinomialNBиBernoulliNBон так и называется —alpha, со значением по умолчаниюalpha=1.0.
Примеры с разбором
Пример 1 (лёгкий, демонстрация проблемы). В обучающей выборке для класса «не спам» слово «виагра» не встретилось ни разу среди 60 слов класса. Новое письмо содержит слова «деньги» и «виагра». Покажи, что происходит с оценкой класса «не спам» без сглаживания, даже если слово «деньги» само по себе не слишком подозрительно (например, $P(\text{«деньги»}\mid\text{не спам})=0{,}05$).
Без сглаживания $P(\text{«виагра»}\mid\text{не спам}) = 0/60 = 0$. Тогда:
$$\text{Score(не спам)} = P(\text{не спам})\cdot P(\text{«деньги»}\mid\text{не спам})\cdot P(\text{«виагра»}\mid\text{не спам}) = 0{,}6\cdot0{,}05\cdot0 = 0.$$Ответ: оценка класса «не спам» обнуляется полностью, вне зависимости от того, насколько слово «деньги» в остальном нейтрально. Даже если бы в письме было ещё десять совершенно обычных, характерных для деловой переписки слов, единственное невиданное слово «виагра» перечеркнуло бы их все — классификатор автоматически и безальтернативно отнесёт письмо к спаму просто из-за отсутствия «виагры» в истории обучающих данных, а не из-за реального анализа содержания.
Пример 2 (средний, применение сглаживания). Дополним обучающую выборку из первого примера урока: в классе «спам» слово «виагра» встретилось 5 раз (при общем числе слов в классе, увеличившемся до 45 из-за добавленных вхождений), в классе «не спам» — по-прежнему 0 раз (при 60 словах). Размер словаря $|V|=5$ (слова «деньги», «скидка», «бесплатно», «привет», «виагра»). Примени сглаживание Лапласа с $\alpha=1$ и пересчитай классификацию письма «деньги виагра», используя ранее посчитанные счётчики слова «деньги» (8 в спаме, 3 в не спаме) и приоры $P(\text{спам})=0{,}4$, $P(\text{не спам})=0{,}6$.
Сглаженные вероятности для класса «спам» (знаменатель $\text{count}(c)+\alpha|V| = 45+5=50$):
$$P(\text{«деньги»}\mid\text{спам}) = \frac{8+1}{50}=0{,}18, \qquad P(\text{«виагра»}\mid\text{спам}) = \frac{5+1}{50}=0{,}12.$$Сглаженные вероятности для класса «не спам» (знаменатель $60+5=65$):
$$P(\text{«деньги»}\mid\text{не спам}) = \frac{3+1}{65}\approx0{,}0615, \qquad P(\text{«виагра»}\mid\text{не спам}) = \frac{0+1}{65}\approx0{,}0154.$$Перемножаем и нормируем:
$$\text{Score(спам)} = 0{,}4\cdot0{,}18\cdot0{,}12 \approx 0{,}00864, \qquad \text{Score(не спам)} = 0{,}6\cdot0{,}0615\cdot0{,}0154 \approx 0{,}000568,$$$$P(\text{спам}\mid x) = \frac{0{,}00864}{0{,}00864+0{,}000568} \approx 0{,}938.$$
Ответ: после сглаживания письмо по-прежнему классифицируется как спам, но уже честно — с вероятностью около $93{,}8\%$, а не с механическим нулём для альтернативного класса. Слово «виагра» получило маленькую, но ненулевую вероятность и для класса «не спам» ($\approx1{,}5\%$), что отражает реальную неопределённость: это слово теоретически может встретиться и в обычной переписке (например, в письме от фармацевта коллеге), просто мы такого случая не видели в обучающих данных.
Пример 3 (сложный, подбор параметра $\alpha$). Сравни эффект сглаживания при $\alpha=1$ (классический Лаплас) и при $\alpha=2$ на примере признака с $\text{count}(w,c)=0$, $\text{count}(c)=30$, $|V|=15$.
При $\alpha=1$: $P(w\mid c) = \dfrac{0+1}{30+1\cdot15} = \dfrac{1}{45} \approx 0{,}0222$.
При $\alpha=2$: $P(w\mid c) = \dfrac{0+2}{30+2\cdot15} = \dfrac{2}{60} \approx 0{,}0333$.
Ответ: увеличение $\alpha$ с 1 до 2 почти на треть увеличивает сглаженную вероятность невиданного слова (с $2{,}2\%$ до $3{,}3\%$) — большее $\alpha$ означает более сильное «доверие по умолчанию» к признакам, которых не было в обучающей выборке, за счёт выравнивания различий между часто и редко встречавшимися словами. Слишком маленький $\alpha$ оставляет проблему нулевых вероятностей почти нерешённой (сглаживание едва заметно), а слишком большой $\alpha$ делает все слова в классе почти одинаково вероятными, стирая полезный сигнал, который несут действительно характерные слова, — поэтому на практике значение $\alpha$ имеет смысл подбирать по кросс-валидации, а не использовать значение по умолчанию не глядя.
Почему это важно. Сглаживание Лапласа — не косметическая деталь формулы, а обязательное условие того, чтобы наивный Байес вообще работал на реальных данных: любой достаточно большой словарь неизбежно порождает слова, которые встретились в обучающей выборке для одного класса, но ни разу — для другого, и без сглаживания даже одно такое слово полностью и необратимо разрушает классификацию этого класса. Все промышленные реализации — GaussianNB (через параметр var_smoothing, добавляемый к дисперсии), MultinomialNB и BernoulliNB (через параметр alpha) — применяют сглаживание по умолчанию именно по этой причине.
Практика: 30 заданий
Базовые (задания 1–10)
Задание 1. Редкое заболевание встречается у 1% населения. Тест верно обнаруживает болезнь у 95% больных и даёт ложноположительный результат у 5% здоровых. Пациент получил положительный результат. Найди вероятность того, что он действительно болен, по теореме Байеса.
Задание 2. Дано: $P(\text{класс})=0{,}3$, $P(\text{признак}\mid\text{класс})=0{,}8$, $P(\text{признак})=0{,}5$. Найди $P(\text{класс}\mid\text{признак})$.
Задание 3. Запиши формулу наивного Байеса для совместной условной вероятности двух признаков $x_1$ и $x_2$ при известном классе $c$, используя предположение об условной независимости.
Задание 4. Дано: $P(\text{спам})=0{,}4$, $P(\text{«скидка»}\mid\text{спам})=0{,}6$, $P(\text{не спам})=0{,}6$, $P(\text{«скидка»}\mid\text{не спам})=0{,}1$. Письмо содержит слово «скидка». Вычисли непронормированные оценки для обоих классов и определи класс.
Задание 5. В классе «спам» суммарно 50 слов, слово «приз» встречается 10 раз. Найди $P(\text{«приз»}\mid\text{спам})$ без сглаживания.
Задание 6. Слово «приз» ни разу не встретилось среди 80 слов класса «не спам». Объясни, что произойдёт с итоговой оценкой класса «не спам», если письмо содержит слово «приз», а сглаживание не применяется.
Задание 7. Примени сглаживание Лапласа ($\alpha=1$) для слова «приз» из предыдущего задания: размер словаря $|V|=200$, $\text{count}(\text{«приз»},\text{не спам})=0$, $\text{count}(\text{не спам})=80$. Найди сглаженную вероятность.
Задание 8. Признак распределён нормально внутри класса: $\mu=50$, $\sigma^2=16$. Вычисли значение плотности вероятности $f(x=54)$.
Задание 9. Сформулируй формулой, что означает условная независимость признаков $x_1,\dots,x_n$ при заданном классе $c$.
Задание 10. В бернуллиевской модели слово «акция» присутствует в 3 из 5 спам-писем. Найди оценку параметра $p=P(\text{присутствует}\mid\text{спам})$ без сглаживания.
Средние (задания 11–20)
Задание 11. Дано: $P(\text{спам})=0{,}5$, $P(\text{не спам})=0{,}5$, письмо содержит слова «деньги» и «приз». $P(\text{«деньги»}\mid\text{спам})=0{,}4$, $P(\text{«приз»}\mid\text{спам})=0{,}3$, $P(\text{«деньги»}\mid\text{не спам})=0{,}05$, $P(\text{«приз»}\mid\text{не спам})=0{,}02$. Классифицируй письмо.
Задание 12. В обучающей выборке из 8 писем (5 спам, 3 не спам) слово «клик» встречается в спам-классе 12 раз при общем числе слов в классе 60, а в не спам-классе — 2 раза при общем числе слов 40. Найди $P(\text{«клик»}\mid\text{спам})$ и $P(\text{«клик»}\mid\text{не спам})$ без сглаживания.
Задание 13. Используя данные предыдущего задания и приоры $P(\text{спам})=5/8=0{,}625$, $P(\text{не спам})=3/8=0{,}375$, найди, во сколько раз оценка класса «спам» больше оценки класса «не спам» для письма с единственным словом «клик».
Задание 14. Gaussian NB, два класса с равными приорами: класс А — $\mu=100$, $\sigma^2=64$; класс Б — $\mu=130$, $\sigma^2=64$. Для объекта $x=110$ определи, какой класс выбрать, сравнив показатели степени экспоненты (общий множитель $1/\sqrt{2\pi\sigma^2}$ одинаков для обоих классов и не влияет на сравнение).
Задание 15. Примени обобщённое аддитивное сглаживание с параметром $\alpha=2$: $\text{count}(w,c)=0$, $\text{count}(c)=30$, $|V|=15$. Найди $P(w\mid c)$.
Задание 16. Bernoulli NB: документ описан вектором присутствия признаков $[1,0,1]$, параметры класса $c$: $p_1=0{,}7$, $p_2=0{,}4$, $p_3=0{,}6$. Вычисли $P(x\mid c)$.
Задание 17. Тот же документ $[1,0,1]$ для другого класса с параметрами $p_1=0{,}2$, $p_2=0{,}3$, $p_3=0{,}9$. Вычисли $P(x\mid\text{класс2})$ и сравни с результатом предыдущего задания.
Задание 18. Multinomial NB: документ описан вектором частот $(2,0,1)$ для слов $(w_1,w_2,w_3)$. Параметры класса: $P(w_1\mid c)=0{,}5$, $P(w_2\mid c)=0{,}3$, $P(w_3\mid c)=0{,}2$. Вычисли произведение $\prod P(w_i\mid c)^{\text{count}_i}$.
Задание 19. Перепиши формулу наивного Байеса $P(c)\prod_i P(x_i\mid c)$ в логарифмическом виде и объясни, зачем на практике используют именно логарифмы, а не прямое перемножение вероятностей.
Задание 20. Дано: $\log P(\text{спам})=-0{,}916$, сумма логарифмов условных вероятностей слов для спама $=-5{,}2$; $\log P(\text{не спам})=-0{,}511$, сумма для не спама $=-9{,}8$. Сравни логарифмические оценки и выбери класс.
Продвинутые (задания 21–30)
Задание 21. Докажи, что максимизация $P(c\mid x_1,\dots,x_n)$ эквивалентна максимизации $P(c)\cdot P(x_1,\dots,x_n\mid c)$, если знаменатель теоремы Байеса $P(x_1,\dots,x_n)$ не зависит от класса.
Задание 22. Обучающая выборка: в классе «спам» всего 50 слов, слово «бонус» встретилось 10 раз, «встреча» — 0 раз. В классе «не спам» всего 70 слов, «бонус» — 1 раз, «встреча» — 14 раз. Размер словаря $|V|=100$. Приоры $P(\text{спам})=0{,}3$, $P(\text{не спам})=0{,}7$. Письмо содержит слова «бонус» и «встреча». Используя сглаживание Лапласа ($\alpha=1$), классифицируй письмо.
Задание 23. Повтори расчёт предыдущего задания без сглаживания Лапласа (используй «сырые» частоты) и объясни разницу с результатом задания 22.
Задание 24. Gaussian NB для одного признака «вес»: класс «спортсмен» имеет $\mu=75$, $\sigma^2=25$. Найди отношение плотности вероятности в точке $x=70$ к плотности вероятности в точке максимума $x=75$ (то есть $f(70)/f(75)$).
Задание 25. Объясни своими словами разницу между генеративным подходом наивного Байеса (моделирует $P(x\mid c)$ и $P(c)$ отдельно, затем применяет теорему Байеса) и дискриминативным подходом логистической регрессии (моделирует $P(c\mid x)$ напрямую).
Задание 26. Multinomial NB, тональность отзывов: $P(\text{«отлично»}\mid\text{позитив})=0{,}15$, $P(\text{«плохо»}\mid\text{позитив})=0{,}02$, $P(\text{«отлично»}\mid\text{негатив})=0{,}03$, $P(\text{«плохо»}\mid\text{негатив})=0{,}18$, приоры равны. Отзыв содержит «отлично» дважды и «плохо» один раз. Найди оценки обоих классов и определи тональность.
Задание 27. Объясни, почему для мультиномиального наивного Байеса важно, чтобы сумма $P(w\mid c)$ по всем словам словаря внутри одного класса равнялась единице, а не просто была числом между 0 и 1 для каждого слова по отдельности. Проверь на словаре из трёх слов с счётчиками $3, 5, 2$ (всего $10$ слов в классе).
Задание 28. Объясни, почему обучение MultinomialNB на датасете из миллиона текстовых документов со словарём в 50 000 слов занимает доли секунды, тогда как обучение логистической регрессии на тех же данных требует заметно больше времени.
Задание 29. Для бернуллиевского варианта наивного Байеса примени сглаживание Лапласа по формуле $p=(\text{count}+1)/(n+2)$ (знаменатель увеличивается на 2, потому что у бинарного признака ровно два исхода — присутствие и отсутствие). Дано: $\text{count}=0$, $n=6$. Найди сглаженную $p$.
Задание 30. Интегральная задача. Обучающая выборка из 20 SMS (8 спам, 12 не спам). В спам-классе 80 слов, слово «приз» встречается 16 раз, «звонок» — 4 раза. В не спам-классе 150 слов, «приз» встречается 2 раза, «звонок» — 20 раз. Словарь $|V|=300$. Приоры $P(\text{спам})=8/20=0{,}4$, $P(\text{не спам})=12/20=0{,}6$. Классифицируй SMS «приз звонок», применяя сглаживание Лапласа ($\alpha=1$).
Частые ошибки
❌ Ошибка: забывать сглаживание Лапласа и получать нулевую вероятность класса из-за одного невиданного слова
✅ Правильно: всегда применять аддитивное сглаживание (в sklearn это параметр alpha, включённый по умолчанию), даже если кажется, что обучающая выборка достаточно большая
💡 Почему: какой бы большой ни была обучающая выборка, всегда найдётся слово или комбинация признаков, которая ни разу не встретилась для конкретного класса — а один нулевой множитель обнуляет всё произведение вероятностей, полностью игнорируя остальные, зачастую куда более информативные признаки объекта
❌ Ошибка: считать, что раз наивное предположение о независимости признаков нарушается в реальных данных, то наивный Байес — заведомо плохая модель ✅ Правильно: оценивать модель по итоговому качеству классификации, а не по формальной корректности предположений 💡 Почему: для классификации важен не точный абсолютный уровень вероятности, а то, какой класс получает наибольшую оценку; нарушение независимости искажает масштаб оценок, но часто не меняет их порядок, особенно если классы разделены отчётливо
❌ Ошибка: подавать непрерывные числовые признаки (рост, доход, температуру) в MultinomialNB или BernoulliNB без преобразования
✅ Правильно: использовать GaussianNB для непрерывных признаков, MultinomialNB — для счётных данных (частоты слов), BernoulliNB — для бинарных признаков «есть/нет»
💡 Почему: каждый вариант наивного Байеса оценивает свой тип статистики (среднее и дисперсию, доли вхождений, доли присутствия в документах) — несоответствие типа признака и варианта модели даёт формально работающий, но статистически бессмысленный расчёт
❌ Ошибка: доверять числам из predict_proba() наивного Байеса как точным, откалиброванным вероятностям
✅ Правильно: воспринимать эти числа как ранжирующий сигнал (какой класс более вероятен), а не как точную оценку уверенности модели
💡 Почему: из-за наивного предположения о независимости итоговые оценки систематически смещаются к экстремальным значениям, близким к 0 или 1, даже когда объект находится на границе между классами; для откалиброванных вероятностей поверх наивного Байеса применяют дополнительную калибровку (например, изотоническую регрессию)
❌ Ошибка: перемножать вероятности напрямую вместо перехода к сумме логарифмов при большом числе признаков
✅ Правильно: работать в логарифмической шкале — использовать predict_log_proba или вручную суммировать логарифмы вероятностей
💡 Почему: произведение сотен и тысяч чисел меньше единицы (как в классификации текста с большим словарём) стремительно уходит к нулю и теряется в ограниченной машинной точности чисел с плавающей запятой, а сумма логарифмов этой проблемы не имеет
❌ Ошибка: игнорировать дисбаланс классов в обучающей выборке при оценке априорных вероятностей ✅ Правильно: учитывать, что $P(c)$ напрямую оценивается по доле каждого класса в обучающих данных, и при сильном дисбалансе корректировать её вручную или использовать взвешивание 💡 Почему: если спама в обучающей выборке искусственно мало (например, 2% против 98% обычных писем в реальном трафике), заниженный приор $P(\text{спам})$ будет систематически перетягивать классификатор в сторону «не спам» даже для писем с явно спамерскими признаками
Главное запомнить
✅ Теорема Байеса переворачивает вопрос «какова вероятность причины при известном следствии» в вопрос «какова вероятность следствия при известной причине» — вторую вероятность значительно проще оценить по обучающим данным
✅ Байесовский классификатор выбирает класс, максимизирующий $P(c)\cdot P(x_1,\dots,x_n\mid c)$ — знаменатель теоремы Байеса можно отбросить, так как он не зависит от класса
✅ «Наивное» предположение заключается в условной независимости признаков при заданном классе: $P(x_1,\dots,x_n\mid c) = \prod_i P(x_i\mid c)$ — почти никогда не выполняется точно, но резко сокращает число параметров, которые нужно оценить по данным
✅ Наивный Байес часто даёт верную классификацию даже при нарушенной независимости признаков, потому что для сравнения классов важен порядок оценок, а не их точный абсолютный уровень
✅ Три классических варианта: GaussianNB — для непрерывных признаков (нормальное распределение внутри класса), MultinomialNB — для счётных данных вроде частот слов, BernoulliNB — для бинарных признаков «присутствует/отсутствует», явно учитывающих и отсутствие ожидаемого признака
✅ sklearn.naive_bayes.MultinomialNB — классический стандартный инструмент базовой классификации текста (спам-фильтры, анализ тональности) благодаря почти мгновенному обучению без итеративной оптимизации — только подсчёт частот — и приемлемому качеству на разреженных текстовых признаках
✅ Сглаживание Лапласа $P(w\mid c) = (\text{count}(w,c)+\alpha)/(\text{count}(c)+\alpha|V|)$ решает проблему нулевой вероятности для слов, не встретившихся в обучающей выборке класса; без него один невиданный признак обнуляет оценку всего класса
✅ Параметр сглаживания $\alpha$ (по умолчанию $1$, классическое сглаживание Лапласа) стоит подбирать по кросс-валидации: слишком маленькое значение почти не решает проблему нулевых вероятностей, слишком большое — стирает различия между классами
✅ Наивный Байес — генеративная модель: она моделирует распределение признаков внутри каждого класса и получает $P(c\mid x)$ через теорему Байеса, в отличие от дискриминативных моделей вроде логистической регрессии, напрямую обучающих $P(c\mid x)$
✅ На практике вероятности умножают в логарифмической шкале ($\log P(c) + \sum_i \log P(x_i\mid c)$), чтобы избежать потери точности при перемножении множества малых чисел
Связь с темами курса
🔙 Откуда пришли: Из урока 232 («Формула Байеса») — сама теорема Байеса, лежащая в основе наивного классификатора, была впервые разобрана именно там как инструмент теории вероятностей задолго до её применения к машинному обучению; из урока 314 (k-Nearest Neighbors) — понимание того, что не все алгоритмы классификации одинаково устроены: kNN не строит явную модель и хранит все данные, наивный Байес, наоборот, строит явную вероятностную модель и не нуждается в хранении обучающей выборки при предсказании
🔜 Куда ведёт:
- Деревья решений (урок 316) — ещё один способ построить классификатор, но уже не вероятностный, а основанный на последовательных проверках признаков; полезно сравнить оба подхода по интерпретируемости и по устойчивости к коррелированным признакам
- Логистическая регрессия (урок 313, уже пройден) — дискриминативная альтернатива генеративному наивному Байесу; полезно вернуться к ней и осмыслить разницу генеративного и дискриминативного подходов на конкретном примере
- Ансамблевые методы (Random Forest, Gradient Boosting, уроки 317–318) — там, где предположение о независимости признаков наивного Байеса становится критичным ограничением, ансамбли деревьев решений умеют естественно учитывать взаимодействия между признаками
🎯 В машинном обучении: оценка параметров наивного Байеса по частотам — это в чистом виде метод максимального правдоподобия для распределений Бернулли, мультиномиального и нормального, разобранный в уроке 246: доля вхождений слова в частотной модели $P(w\mid c)=\text{count}(w,c)/\text{count}(c)$ — это ровно ММП-оценка параметра мультиномиального распределения, а среднее и дисперсия в GaussianNB — это ММП-оценки параметров нормального распределения. Наивный Байес — наглядный пример того, как общий статистический принцип (максимизация правдоподобия данных) напрямую превращается в работающий алгоритм классификации без единого шага градиентного спуска.
Интересные факты
📌 Томас Байес никогда не публиковал свою теорему при жизни — рукопись обнаружили среди его бумаг после смерти в 1761 году, и её подготовил к публикации друг и коллега Ричард Прайс, представивший работу Королевскому обществу в 1763 году. Байес, по всей видимости, даже не подозревал, что его имя переживёт века.
📌 Наивный Байес нередко превосходит по качеству классификации гораздо более сложные модели именно на задачах с высокоразмерными разреженными признаками (как частоты слов в тексте) — этот на первый взгляд парадоксальный факт был формально исследован в статье Педро Домингоса и Майкла Пазцани «On the Optimality of the Simple Bayesian Classifier under Zero-One Loss» (1997), объяснившей, почему нарушенное предположение о независимости признаков редко портит итоговую классификацию.
📌 Массовую популярность байесовская фильтрация спама получила после эссе программиста Пола Грэма «A Plan for Spam» (2002), в котором простой наивный байесовский фильтр, обучаемый на личной переписке конкретного пользователя, показал результаты заметно лучше, чем статичные списки правил и чёрные списки отправителей, использовавшиеся почтовыми клиентами того времени.
📌 Сглаживание Лапласа названо в честь Пьера-Симона Лапласа, который ещё в XVIII веке применял похожую идею аддитивной коррекции, рассуждая над «задачей о восходе солнца» — как оценить вероятность того, что солнце взойдёт завтра, если оно неизменно восходило каждый день на протяжении всей письменной истории. Спустя более двухсот лет тот же математический приём спасает наивный Байес от нулевых вероятностей в спам-фильтрах.
📌 Несмотря на «наивность» модели, гауссовский наивный Байес при равных дисперсиях классов даёт линейную разделяющую границу между классами — то есть по форме итогового решения он в определённых условиях эквивалентен линейной модели, похожей по духу на логистическую регрессию, хотя обучается совершенно иным (генеративным, а не дискриминативным) способом.
Лайфхаки
💡 Всегда работай в логарифмической шкале вероятностей (predict_log_proba в sklearn), а не перемножай вероятности напрямую — на большом словаре или большом числе признаков прямое произведение множества дробей меньше единицы стремительно уходит к нулю и теряется в машинной точности чисел с плавающей запятой.
💡 Выбирай вариант наивного Байеса строго по типу признаков: непрерывные числовые значения — GaussianNB, счётные частоты (например, число вхождений слова) — MultinomialNB, бинарные признаки присутствия — BernoulliNB. Смешение типов признаков внутри одной модели без преобразования — частый источник незаметно заниженного качества.
💡 Не оставляй параметр сглаживания alpha со значением по умолчанию не глядя — подбирай его по кросс-валидации, особенно если словарь признаков большой, а обучающая выборка сравнительно небольшая: слишком маленький alpha не решает проблему нулевых вероятностей, слишком большой стирает полезные различия между классами.
💡 Используй наивный Байес как быстрый и сильный базовый вариант («бейзлайн») перед тем, как переходить к более тяжёлым моделям классификации текста: обучение MultinomialNB на большом корпусе занимает секунды, а качество на многих практических задачах (спам-фильтрация, простая классификация тональности) оказывается достаточно конкурентоспособным, чтобы сразу понять, стоит ли усложнять пайплайн.
💡 Избегай включения в один и тот же набор признаков сильно коррелирующих между собой характеристик (например, сырых частот слов вместе с их TF-IDF-версией) — усиленное нарушение независимости признаков может сместить итоговые оценки заметнее, чем обычно, особенно когда классы близки друг к другу по составу признаков.
💡 Если тебе важны не только правильные метки классов, но и откалиброванные вероятности (например, для принятия решений с учётом стоимости ошибки), не доверяй сырым выводам predict_proba наивного Байеса напрямую — примени поверх них калибровку вероятностей (CalibratedClassifierCV в sklearn), потому что наивное предположение о независимости систематически завышает уверенность модели.
Ты прошёл путь от перевёрнутого вопроса Томаса Байеса — «какова вероятность причины при известном следствии» — до полноценного, работающего классификатора текста, способного за доли секунды отделить спам от обычной переписки по частотам отдельных слов. По пути ты увидел, как заведомо неверное упрощение — предположение о независимости признаков — не разрушает алгоритм, а делает его практичным: вместо неподъёмной задачи оценки совместного распределения тысяч слов наивный Байес решает тысячу маленьких, легко считаемых задач и получает результат, который на практике конкурирует с моделями, честно учитывающими все взаимосвязи между признаками. В следующем уроке ты познакомишься с деревьями решений — алгоритмом, который подходит к классификации совершенно иначе, без единой вероятности, а через последовательность простых вопросов о значениях признаков, и это станет хорошим поводом сравнить, во что обходится интерпретируемость модели в каждом из этих двух принципиально разных подходов.
Понял тему? Закрепи в боте! 🚀
Попрактикуйся на задачах и получи персональные рекомендации от AI
💪 Начать тренировку