Объединение индивидуальных вероятностей в наивной байесовской фильтрации спама - PullRequest
19 голосов
/ 24 июня 2011

В настоящее время я пытаюсь сгенерировать спам-фильтр, анализируя накопленный мной корпус.

Я использую запись в википедии http://en.wikipedia.org/wiki/Bayesian_spam_filtering для разработки классификационного кода.

Я реализовал код для вычисления вероятности того, что сообщение является спамом, учитывая, что оно содержит определенное слово, путем реализации следующей формулы из вики:

pr(S|W) = (pr(W|S)*pr(S))/(pr(W|S)*pr(S) + pr(W|H)*pr(H))

Мой код PHP:

public function pSpaminess($word)
{
    $ps = $this->pContentIsSpam();
    $ph = $this->pContentIsHam();
    $pws = $this->pWordInSpam($word);
    $pwh = $this->pWordInHam($word);
    $psw = ($pws * $ps) / ($pws * $ps + $pwh * $ph);
    return $psw;
}

В соответствии с разделом «Объединение отдельных вероятностей» я реализовал код, объединяющий вероятности всех уникальных слов в тестовом сообщении для определения нежелательности.

Из формулы вики:

p=(p1*pn)/((p1*pn)+(1-p)(1-pn))

Мой код PHP:

public function predict($content)
{
    $words = $this->tokenize($content);
    $pProducts = 1;
    $pSums = 1;
    foreach($words as $word)
    {
        $p = $this->pSpaminess($word);
        echo "$word: $p\n";
        $pProducts *= $p;
        $pSums *= (1 - $p);
    }
    return $pProducts / ($pProducts + $pSums);
}

На тестовой строке «Это совсем не плохо.» Выдается следующий вывод:

C:\projects\bayes>php test.php
this: 0.19907407407407
isn't: 0.23
very: 0.2
bad: 0.2906976744186
at: 0.17427385892116
all: 0.16098484848485
probability message is spam: float(0.00030795502523944)

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

Меня беспокоит действительно малая результирующая вероятность расчета. Я проверил его в более крупном тестовом сообщении и в результате получил научную запись с вероятностью более 10 мест с нулями. Я ожидал значения в десятых или сотых местах.

Я надеюсь, что проблема заключается в моей реализации PHP - но когда я рассматриваю функцию комбинирования из википедии, дивиденд формулы вычисляется как произведение дробей. Я не понимаю, как комбинация множественных вероятностей может оказаться даже больше, чем 0,1% вероятности.

Если это так, то чем длиннее сообщение, тем ниже будет оценка вероятности, как я могу компенсировать квоту нежелательности, чтобы правильно предсказать спам / ветчину для малых и больших тестовых случаев?


Дополнительная информация

Мой корпус на самом деле представляет собой коллекцию около 40 тыс. Комментариев Reddit. Я на самом деле применяю свой «фильтр спама» против этих комментариев. Я оцениваю отдельный комментарий как спам / хам, основываясь на количестве голосов «за» и «против»: если количество голосов «против» меньше количества голосов «против», оно считается «Хам», в противном случае - «Спам».

Теперь, из-за типа корпуса, оказалось, что на самом деле мало слов, которые используются в спаме больше, чем в ветчине. То есть вот список из десяти лучших слов, которые встречаются в спаме чаще, чем ветчина.

+-----------+------------+-----------+
| word      | spam_count | ham_count |
+-----------+------------+-----------+
| krugman   |         30 |        27 |
| fetus     |       12.5 |       7.5 |
| boehner   |         12 |        10 |
| hatred    |       11.5 |       5.5 |
| scum      |         11 |        10 |
| reserve   |         11 |        10 |
| incapable |        8.5 |       6.5 |
| socalled  |        8.5 |       5.5 |
| jones     |        8.5 |       7.5 |
| orgasms   |        8.5 |       7.5 |
+-----------+------------+-----------+

Напротив, большинство слов употребляется в изобилии в хаме больше, чем в хамоне. Возьмите, к примеру, мой топ-10 слов с наибольшим количеством спама.

+------+------------+-----------+
| word | spam_count | ham_count |
+------+------------+-----------+
| the  |       4884 |     17982 |
| to   |     4006.5 |   14658.5 |
| a    |     3770.5 |   14057.5 |
| of   |     3250.5 |   12102.5 |
| and  |       3130 |     11709 |
| is   |     3102.5 |   11032.5 |
| i    |     2987.5 |   10565.5 |
| that |     2953.5 |   10725.5 |
| it   |       2633 |      9639 |
| in   |     2593.5 |    9780.5 |
+------+------------+-----------+

Как видите, частота использования спама значительно меньше, чем использование хама. В моем корпусе из 40 тысяч комментариев 2100 комментариев считаются спамом.

Как предложено ниже, тестовая фраза в сообщении оценивается как нежелательная почта следующим образом:

Фраза

Cops are losers in general. That's why they're cops.

Анализ:

C:\projects\bayes>php test.php
cops: 0.15833333333333
are: 0.2218958611482
losers: 0.44444444444444
in: 0.20959269435914
general: 0.19565217391304
that's: 0.22080730418068
why: 0.24539170506912
they're: 0.19264544456641
float(6.0865969793861E-5)

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

Разговорник

Bill and TED's excellent venture?
* * Анализ тысяча шестьдесят три
C:\projects\bayes>php test.php
bill: 0.19534050179211
and: 0.21093065570456
ted's: 1
excellent: 0.16091954022989
venture: 0.30434782608696
float(1)

Хорошо, это интересно. Я делаю эти примеры, когда создаю это обновление, так что я впервые вижу результат для этого конкретного теста. Я думаю, что мой прогноз перевернут. Это фактически выбирает вероятность Хэма вместо Спама. Это заслуживает проверки.

Новый тест на известную ветчину.

Фраза

Complain about $174,000 salary being too little for self.  Complain about $50,000 a year too much for teachers.
Scumbag congressman.
* +1073 * Анализ * +1074 *
C:\projects\bayes>php test.php
complain: 0.19736842105263
about: 0.21896031561847
174: 0.044117647058824
000: 0.19665809768638
salary: 0.20786516853933
being: 0.22011494252874
too: 0.21003236245955
little: 0.21134020618557
for: 0.20980452359022
self: 0.21052631578947
50: 0.19245283018868
a: 0.21149315683195
year: 0.21035386631717
much: 0.20139771283355
teachers: 0.21969696969697
scumbag: 0.22727272727273
congressman: 0.27678571428571
float(3.9604152477223E-11)

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

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


Окончательное обновление

Как указывалось в ответах, странные результаты были связаны с характером корпуса.Использование корпуса комментариев, где нет явного определения спама Байесовская классификация не выполняется.Поскольку возможно (и вероятно), что какой-либо один комментарий может получить как спам, так и рейтинг хама от различных пользователей, невозможно создать жесткую классификацию для спам-комментариев.

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

Ответы [ 3 ]

2 голосов
/ 10 октября 2011

Если ваш фильтр не смещен (Pr (S) = Pr (H) = 0,5), то: «Также рекомендуется, чтобы полученный набор сообщений соответствовал гипотезе 50% о перераспределении между спамом и ветчиной, то есть наборы данных спама и ветчины имеют одинаковый размер. "

Это означает, что вы должны обучать свой байесовский фильтр аналогичному количеству сообщений со спамом и ветчиной. Скажите 1000 спам-сообщений и 1000 ветчинных сообщений.

Я бы предположил (не проверено), что если ваш фильтр смещен, обучающий набор должен соответствовать гипотезе о том, что любое сообщение является спамом.

2 голосов
/ 24 июня 2011

Меняется только с помощью калькулятора. Кажется, это нормально для фразы без спама, которую вы разместили. В этом случае у вас есть $ pProducts на пару порядков величин меньше, чем $ pSums.

Попробуйте запустить настоящий спам из папки со спамом, где вы встретите вероятности, например, 0,8. И угадайте, почему спаммеры иногда пытаются отправить газету в скрытой рамке вместе с сообщением:)

0 голосов
/ 15 ноября 2014

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

...