2011-06-24 16 views
17

Actualmente estoy intentando generar un filtro de spam mediante el análisis de un corpus que he acumulado.Combinando las probabilidades individuales en el filtro de spam de Naive Bayesian

Estoy usando la entrada de la wikipedia http://en.wikipedia.org/wiki/Bayesian_spam_filtering para desarrollar mi código de clasificación.

he implementado código para calcular la probabilidad de que un mensaje se le da el spam que contiene una palabra específica mediante la aplicación de la siguiente fórmula de la wiki:

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

Mi código 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; 
} 

De acuerdo con la sección de la combinación de probabilidades individuales, he implementado el código para combinar las probabilidades de todas las palabras únicas en un mensaje de prueba para determinar el spaminess.

De la fórmula wiki:

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

Mi código 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); 
} 

En una cadena de prueba "Esto no es muy mal", se produce la siguiente salida :

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) 

Aquí está mi pregunta: ¿Estoy implementando la combinación de indiv probabilidades iduales correctamente? Suponiendo que estoy generando probabilidades de palabras individuales válidas, ¿es correcto el método de combinación?

Mi preocupación es la muy pequeña probabilidad resultante del cálculo. Lo probé en un mensaje de prueba más grande y terminé con una probabilidad resultante en notación científica con más de 10 lugares de ceros. Esperaba valores en los lugares 10 o 100.

Espero que el problema radique en mi implementación de PHP, pero cuando examino la función de combinación de wikipedia, el dividendo de la fórmula es un producto de fracciones. No veo cómo una combinación de múltiples probabilidades terminaría siendo más de .1% de probabilidad.

Si es el caso, de modo que cuanto más largo sea el mensaje, menor será la puntuación de probabilidad, ¿cómo compensaré la cuota de spaminess para predecir correctamente spam/ham para casos de prueba pequeños y grandes?


Información adicional

Mi corpus es en realidad una colección de cerca de 40 mil comentarios reddit. De hecho, estoy aplicando mi "filtro de spam" en contra de estos comentarios. Califico un comentario individual como spam/ham en función del número de votos rechazados para subir los votos: si los votos al alza son menores que los votos hacia abajo, se considera Ham, de lo contrario Spam.

Ahora, debido al tipo de corpus, resulta que en realidad hay pocas palabras que se utilizan en el spam más que en el jamón. Es decir, aquí hay una lista de las diez mejores palabras que aparecen en el correo no deseado con más frecuencia que el jamón.

+-----------+------------+-----------+ 
| 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 | 
+-----------+------------+-----------+ 

Por el contrario, la mayoría de las palabras son utilizadas en gran abundancia en el jamón más que el jamón.Tomemos, por ejemplo, mi lista de las 10 mejores palabras con el mayor conteo de spam.

+------+------------+-----------+ 
| 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 | 
+------+------------+-----------+ 

Como puede ver, la frecuencia de uso de spam es significativamente menor que el uso de jamón. En mi corpus de 40k, se consideran 2100 comentarios como spam.

Como sugieren a continuación, una frase de prueba en un poste considerado tasas de spam de la siguiente manera:

Frase

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

Análisis:

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) 

De acuerdo con esto, existe una muy baja probabilidad de que esto sea spam. Sin embargo, si tuviera que analizar ahora un comentario jamón:

Frase

Bill and TED's excellent venture? 

Análisis

C:\projects\bayes>php test.php 
bill: 0.19534050179211 
and: 0.21093065570456 
ted's: 1 
excellent: 0.16091954022989 
venture: 0.30434782608696 
float(1) 

Bueno, esto es interesante. Estoy haciendo estos ejemplos mientras compongo esta actualización, así que esta es la primera vez que veo el resultado para este caso de prueba específico. Creo que mi predicción está invertida. En realidad, selecciona la probabilidad de Ham en lugar de Spam. Esto merece validación.

Nueva prueba en jamón conocido.

Frase

Complain about $174,000 salary being too little for self. Complain about $50,000 a year too much for teachers. 
Scumbag congressman. 

Análisis

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) 

Desafortunadamente no. Resulta que fue un resultado casual. Estoy comenzando a preguntarme si quizás los comentarios no se puedan cuantificar tan fácilmente. Tal vez la naturaleza de un comentario negativo es demasiado diferente de la naturaleza de un mensaje de spam.

¿Puede ser que el filtrado de spam solo funcione cuando tiene una clase de palabra específica de mensajes de correo no deseado?


Informe final de actualización

Como se señaló en las respuestas, los resultados eran extraños debido a la naturaleza del corpus. Usando un corpus de comentarios donde no hay una definición explícita de spam, la clasificación bayesiana no funciona. Dado que es posible (y probable) que cualquier comentario reciba calificaciones de spam y ham por parte de varios usuarios, no es posible generar una clasificación difícil para los comentarios de correo no deseado.

En última instancia, quería generar un clasificador de comentarios que pudiera determinar si una publicación de comentarios adornaría el karma según una clasificación bayesiana sintonizada para comentar el contenido. Es posible que todavía investigue sintonizar el clasificador para enviar mensajes de spam por correo electrónico y ver si dicho clasificador puede adivinar la respuesta de karma para los sistemas de comentarios. Pero por ahora, la pregunta es respondida. Gracias por su aportación a todos ustedes.

+2

+1 para usar expresiones matemáticas! Y código! Y una explicación completa y bien escrita. Desearía poder votar +10. – wallyk

+0

Hola Jeremy. Terminaste usando este algoritmo para el filtrado de spam. Estoy buscando hacer algo similar pero también obtener resultados inconsistentes. –

+0

Hola, Paul. Hice esto como ejercicio, nunca se usó en nada. Por lo que vale, descubrí que, como se menciona a continuación, los resultados coincidían más con mis expectativas cuando proporcioné un corpus de ejemplos de ham/spam iguales. –

Respuesta

2

Varificando con solo la calculadora, parece estar bien para la frase no-spam que ha publicado. En ese caso, tiene $ pProducts un par de magnitudes más pequeñas que $ pSums.

Intenta ejecutar un poco de spam real de tu carpeta de spam, donde cumplirías probabilidades como 0.8. Y adivinar por qué los spammers en algún momento tratan de enviar una hoja de periódico en un marco oculto junto con el mensaje :)

+0

Lamentablemente, como se discutió anteriormente en la información adicional, incluso la evaluación de mensajes de correo no deseado tiene como resultado pequeñas probabilidades indeseables. –

+2

Bueno, su problema es (suponiendo 40000 de las publicaciones de las cuales alrededor de 2000 son correo no deseado) que usted ... no tiene suficiente correo no deseado. Por lo general, en la comunicación por correo electrónico hay algo así como el 95-98% de correo no deseado, al revés. Es por eso que el filtro bayesiano podría parecerse a la detección de mensajes jam. El otro problema que veo es que la palabra más spam tiene algo así como una probabilidad 0.625 de ser spam, eso no es suficiente. Mi consejo para usted sería obtener una base de datos de spam real y enseñarle su filtro con eso: los mensajes de correo no deseado no son tan diferentes, independientemente de si se trata de un correo electrónico o una publicación en el foro. – meteor

2

Si el filtro no está sesgada (Pr (S) = Pr (H) = 0,5) entonces: "Es también es aconsejable que el conjunto de mensajes aprendido se ajuste a la hipótesis del 50% sobre la repartición entre el spam y el jamón, es decir, que los conjuntos de datos de spam y jamón sean del mismo tamaño ".

Esto significa que debe enseñarle a su filtro bayesiano la cantidad similar de mensajes spam y ham. Digamos 1000 mensajes de spam y 1000 mensajes de ham.

Supongo (no verificado) que si su filtro está sesgado, el conjunto de aprendizaje debe ajustarse a la hipótesis de que cualquier mensaje es correo no deseado.

0

En la idea de compensar longitudes de mensaje, puede estimar para cada conjunto las probabilidades de que una palabra de mensaje sea una palabra específica, luego use una distribución de Poisson para estimar la probabilidad de un mensaje de N palabras que contengan esa palabra específica.

Cuestiones relacionadas