В настоящее время я пытаюсь создать спам-фильтр, анализируя собранный мною корпус.
Я использую запись в wikipedia http://en.wikipedia.org/wiki/Bayesian_spam_filtering, чтобы разработать код классификации.
Я реализовал код для вычисления вероятности того, что сообщение является спамом, учитывая, что оно содержит конкретное слово, используя следующую формулу из вики:
Мой 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; }
В соответствии с разделом «Объединять отдельные вероятности» я реализовал код, чтобы объединить вероятности всех уникальных слов в тестовом сообщении для определения спама.
Из формулы wiki:
Мой 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 местами нулей. Я ожидал ценностей в 10-м или 100-м местах.
Я надеюсь, что проблема кроется в моей реализации PHP – но когда я исследую функцию комбинации из википедии, дивиденд формулы является продуктом фракций. Я не вижу, как комбинация множественных вероятностей окажется еще более вероятной .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.
Анализ
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)
К сожалению нет. Оказывается, это был случайный результат. Я начинаю задаваться вопросом, возможно, что комментарии не могут быть так легко подсчитаны. Возможно, характер плохого комментария слишком сильно отличается от характера спам-сообщения.
Возможно, может быть, фильтрация спама работает только тогда, когда у вас есть определенный класс слов спам-сообщений?
Окончательное обновление
Как указывалось в ответах, странные результаты были обусловлены характером корпуса. Использование комманды комментариев, где нет четкого определения спам-байесовской классификации, не выполняется. Поскольку возможно (и, вероятно,), что любой комментарий может получать как рейтинги спама, так и ветчины различными пользователями, невозможно создать жесткую классификацию для комментариев спама.
В конечном счете, я хотел создать классификатор комментариев, который мог бы определить, будет ли комментарий комментария украшать карму на основе байесовской классификации, настроенной на комментарий. Я могу по-прежнему расследовать настройку классификатора на отправку спам-сообщений электронной почты и посмотреть, может ли такой классификатор угадать ответ кармы для систем комментариев. Но на данный момент ответ на этот вопрос. Спасибо всем за ваш вклад.
Вариатизируя только калькулятор, кажется, что вы не указали не-спам-фразу. В этом случае у вас есть $ pProducts пара порядков величин меньше $ pSums.
Попробуйте запустить какой-то настоящий спам из папки спама, где вы встретите вероятностей, таких как 0,8. И угадайте, почему спамеры когда-нибудь пытаются отправить часть газеты в скрытую рамку вместе с сообщением 🙂
Если ваш фильтр не смещен (Pr (S) = Pr (H) = 0,5), то: «Также желательно, чтобы узнаваемый набор сообщений соответствовал 50% -ной гипотезе о перераспределении между спамом и ветчиной, т. Е. Что наборы данных спам и ветчина одинакового размера ».
Это означает, что вы должны научить ваш байесовский фильтр одинаковому количеству сообщений о спаме и ветчине. Скажите 1000 спам-сообщений и 1000 сообщений ветчины.
Я бы предположил (не проверял), что если ваш фильтр является предвзятым, набор обучения должен соответствовать гипотезе о том, что любое сообщение является спамом.
По идее компенсации длины сообщений вы можете оценить для каждого набора вероятности того, что слово сообщения является конкретным словом, а затем использовать распределение пуассона для оценки вероятности сообщения из N слов, содержащих это конкретное слово.