Модель для науки о данных

Как построить и применить наивную байесовскую классификацию для фильтрации спама

Простая реализация эффективной модели

Я считаю, что сегодня почти у каждого есть смартфон, и у многих есть электронная почта или две. Это означает, что вы должны быть знакомы с множеством сообщений, предлагающих большие деньги, фантастические выигрыши в лотерею, отличные подарки и секреты жизни. Мы получаем десятки спамерских сообщений каждый день, если вы не используете хорошо обученные фильтры. Они могут быть вредными, просто раздражающими или занимать много места, но они также могут содержать вирусы или попытки ловли рыбы. В любом случае, мы хотим иметь дело не с контентом. Так что спрос на хорошие спам-фильтры всегда высок.

Позвольте познакомить вас (или напомнить, если вы уже знакомы) с одним из довольно эффективных алгоритмов фильтрации спама: наивной байесовской классификацией. Хотя в пакете scikit-learn уже есть реализация, я хочу воссоздать алгоритм с нуля. Во-первых, я хочу раскрыть логику, скрытую за реализацией. А во-вторых, я хочу показать алгоритм в связке с подготовкой набора данных.

1. Немного теории

Наивная байесовская классификация - это простой вероятностный алгоритм, основанный на том факте, что все функции модели независимы. В контексте спам-фильтра мы предполагаем, что каждое слово в сообщении не зависит от всех других слов, и мы считаем их, не зная контекста.

Наш алгоритм классификации определяет вероятность того, что сообщение является спамом или нет, по состоянию текущего набора слов. Расчет вероятности основан на формуле Байеса, и компоненты формулы вычисляются на основе частот слов во всем наборе сообщений.

Итак, как работает алгоритм?

2. Немного математики

Прежде всего, возьмем формулу Байеса условной вероятности и применим ее к нашей задаче:

Вероятность того, что сообщение, содержащее слова (w1, w2, w3,…), быть спамом, пропорциональна вероятности получения спама, умноженной на произведение вероятностей того, что каждое слово в сообщении принадлежит к спам-сообщению. Что это значит? Для каждого слова в сообщении мы рассчитываем вероятность его попадания в спам. В нашем контексте:

  • P_spam - часть спам-сообщений в нашем датасете
  • P_wi_spam - вероятность того, что слово будет найдено в спамерских сообщениях.

По той же логике мы определяем:

  • P_not_spam - часть неспамовых сообщений в датасете
  • P_wi_non_spam - вероятность того, что слово будет найдено в сообщениях, не относящихся к спаму.

Но мы до сих пор не умеем вычислять вероятности каждого слова. Хотя у нас есть другая формула:

Что же мы имеем здесь:

  • N_vocabulary - количество уникальных слов во всем наборе данных.
  • N_spam - общее количество слов в спаме.
  • N_wi_spam - количество повторов слова во всех спам-сообщениях.
  • Alpha - коэффициент для случаев, когда слово в сообщении отсутствует в нашем датасете.

Вкратце: вероятность того, что слово принадлежит к спам-сообщению, - это частота этого слова в «части спама» нашего набора данных.

Кроме того, та же формула (но с другими значениями) верна для вероятности того, что слово принадлежит к сообщениям, не связанным со спамом.

Математика окончена, но не беспокойтесь - я покажу все значения и формулы на примере набора данных.

3. Набор данных

Для нашей цели мы воспользуемся сборником SMS-сообщений, который был составлен Тьяго А. Алмейда и Хосе Мария Гомес Идальго. Это бесплатно и может быть загружено из Репозитория машинного обучения UCI.

Структура набора данных проста. Он содержит два столбца - один для метки «спам / ветчина», а другой - для текста сообщения.

Он содержит 5572 записи различных сообщений вместе с 747 спам-сообщениями.

sms_data.groupby('Label').count()
Out[6]:
ham 4825
spam 747

У нас достаточно данных, чтобы начать анализ.

4. Подготовка

Перед применением алгоритма нам необходимо подготовить данные. В первую очередь уберем знаки препинания. Затем мы переведем весь текст в нижний регистр и разделим его на отдельные слова.

Следующее, что нужно сделать, это разделить набор данных на данные для обучения и тестирования. Но нам также необходимо сохранить распространение спам-сообщений и сообщений, не относящихся к спаму.

И наконец, мы должны подготовить словарный запас и подсчитать количество отдельных слов в каждом сообщении.

Соедините полученную таблицу количества слов с данными нашего поезда:

И данные готовы.

5. Осуществление

Воспользуемся приведенными выше формулами и определим основные значения:

  • вероятность того, что сообщение будет спамом
Pspam = train_data[‘Label’].value_counts()[‘spam’] / train_data.shape[0]
  • вероятность того, что сообщение не будет спамом
Pham = train_data[‘Label’].value_counts()[‘ham’] / train_data.shape[0]
  • количество слов в спам-сообщениях
Nspam = train_data.loc[train_data[‘Label’] == ‘spam’, 
                       ‘SMS’].apply(len).sum()
  • количество слов в сообщениях, не относящихся к спаму
Nham = train_data.loc[train_data[‘Label’] == ‘ham’,
                      ‘SMS’].apply(len).sum()
  • размер словарного запаса
Nvoc = len(train_data.columns - 3)
  • установить альфа = 1

6. Результаты

Чтобы завершить формулу, мы определим функции для определения вероятности принадлежности данного слова к спамовым и не спамовым сообщениям:

Наша классификационная функция:

После применения функции мы видим впечатляющие результаты на тестовых данных: 99,1% данных были успешно классифицированы.

Для интереса посмотрим на неправильно распознанные сообщения:

Теперь вы знакомы (или освежились в памяти) с одним из самых эффективных алгоритмов классификации спама. Надеюсь, это было полезно и информативно. Вы можете найти записную книжку Jupyter с рабочим примером на моем GitHub:



Приглашаем вас поделиться другими алгоритмами, призванными бороться со спамом.