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:
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:
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.
+1 para usar expresiones matemáticas! Y código! Y una explicación completa y bien escrita. Desearía poder votar +10. – wallyk
Hola Jeremy. Terminaste usando este algoritmo para el filtrado de spam. Estoy buscando hacer algo similar pero también obtener resultados inconsistentes. –
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. –