Bayesscher Spam-Filter (Bayesian spam filter)
Document Sample


nrw.Summit 07
Bayesscher Spam-Filter
(Bayesian spam filter)
Über mich
• Anwendungsentwickler
– PHP, XSLT, Delphi, Perl
• PHP seit Version 3
• papaya CMS
• Weaverslave
2
Bayesscher Filter
• Statischer Filter
• Bayesscher Wahrscheinlichkeitsbegriff
• Mathematiker Thomas Bayes
– (etwa 1702−1761)
3
E-Mail Spam-Filter
• Kombination mit anderen Methoden
• Thunderbird
• „A Plan For Spam“
– http://www.paulgraham.com/spam.html
4
Einsatz
• Bewertung von Texten
– Kommentare
– Forenbeiträge
– Trackback-Seiten
5
Vorteile/Nachteile
• Serverseitig • Langsam
• Barrierefrei • Eher für längere Texte
• Kombinierbar mit
anderen Systemen
• Keine Session
notwendig
6
2 Schritte
• Training
• Bewertung
7
Training
• Trennung eines Textes in Worte
• Bewertung des Textes als Spam/Ham
• Merken wie oft ein Wort Spam/Ham bewertet
wurde
• Zählen
8
Einstufung
• Trennung eines Textes in Worte
• Bestimmung der Anzahl von Spam/Ham-Worten
im Text
• Berechnung der Wahrscheinlichkeiten für den
Text
9
Schritt 1 - Loggen
• Eingegebene Texte werden geloggt
• Typ
– Text, URL, ...
• Sprache
• Text
– Datenschutz!
10
Schritt 2 - Zerlegen
• UTF-8
– 7bit Punctuation
– [\x00-\x26\x28-\x2F\x3A-\x3F\x5B-\x5F\x7B-\x7F]
– Unicode Properties \pP
• Sprachspezifische Ermittlung der Wörter
– Wörter = Array von Bytes
• Lange Wörter
– Bytelänge
• Kurze Wörter
11
Schritt 2 ½ – Tokens Filtern
• Wörter ignorieren
– Sprachspezifisch
• und, ein, der, die, das, ...
– Aus Wortliste entfernen
• Stopwords
– Sprachspezifisch
– Zählen
12
Schritt 3a - Speichern
• Wörter • Kategorien
– Typ – Typ
– Sprache – Sprache
– Einstufung – Einstufung
– Wort – Anzahl
– Anzahl
13
Schritt 3b - Einstufen
• Wahrscheinlichkeit
– Spam
– Ham
• Anzahl
– Kurze Wörter
– Lange Wörter
– Wörter
14
Show Source
• Ausschnitte aus papaya CMS 5
• Lizenz: GPL
15
function checkSpam() {
include_once(PAPAYA_INCLUDE_PATH.'system/base_spamfilter.php');
$spamFilter = &base_spamfilter::getInstance();
$spamProbability = $spamFilter->check(
@(string)$this->params['entry_text'],
$this->module->parentObj->getContentLanguageId());
$spamFilter->log(
@(string)$this->params['entry_text'],
$this->module->parentObj->getContentLanguageId(),
'Forum Entry Text');
if ($spamProbability['spam'] && defined('PAPAYA_SPAM_BLOCK') && PAPAYA_SPAM_BLOCK) {
return FALSE;
} else {
return TRUE;
}
}
16
function check($string, $lngId) {
$this->_initializeWordLists($lngId);
$tokenData = $this->_getTokens($string, $lngId);
$stopWordData = $this->_countStopWords($tokenData['tokens'], $lngId);
$scores = $this->_categorize($tokenData['tokens'], $lngId);
//initialize default options
...
//get a simple single value rating
if ($scores['HAM'] > $scoreMin && $scores['SPAM'] < $scoreMax &&
$stopWordData[0] < $stopWordMax) {
$isSpam = FALSE;
} else {
$isSpam = TRUE;
}
//return rating and details
return array(
'spam' => $isSpam,
'scores' => $scores,
'stopwordcount' => $stopWordData[0],
'stopwords' => $stopWordData[1],
'scoretokencount' => count($tokenData['tokens']),
'smalltokencount' => $tokenData['smalltokens'],
'largetokencount' => $tokenData['largetokens'],
'blocktokencount' => $tokenData['blocktokens']
);
}
17
function _getTokens($string, $lngId) {
$result = array(
'tokens' => array(),
'smalltokens' => 0,
'largetokens' => 0,
'blocktokens' => 0
);
if ($tokens = preg_split('~['.$this->nonWordChars.']+~', $string)) {
foreach ($tokens as $token) {
if ($this->caseSensitive) {
$token = trim($token);
} else {
$token = papaya_strings::strtolower(trim($token));
}
if ('' == $token || isset($this->ignoreWords[$lngId][$token])) {
//ignore token
} elseif (strlen($token) < $this->minTokenLength) {
++$result['smalltokens'];
} else {
if (strlen($token) > $this->blockTokenLength) {
++$result['blocktokens'];
} elseif (strlen($token) > $this->maxTokenLength) {
++$result['largetokens'];
}
if (isset($result['tokens'][$token])) {
++$result['tokens'][$token];
} else {
$result['tokens'][$token] = 1;
}
}
}
}
return $result;
}
18
function _categorize($tokens, $lngId) {
$scores = array();
if (is_array($tokens) && count($tokens) > 0) {
if (!isset($this->categories[$lngId])) {
//load category data
$this->_loadCategories($lngId);
}
if (isset($this->categories[$lngId])) {
$categories = &$this->categories[$lngId];
$categoryTotals = count($categories);
$wordTotals = $this->categories['TOTALS'][$lngId];
//load word data
$words = $this->_loadWords(array_keys($tokens), $lngId);
foreach ($categories as $categoryIdent => $categoryData) {
$scores[$categoryIdent] = $categoryData['spamcategory_probability'];
// probability for an unknown word
$unknownProbability = 1.0 / ($categoryData['spamcategory_words'] * 2);
foreach ($tokens as $token => $tokenCount) {
if (isset($words['EXISTS'][$token])) {
if (isset($words['DATA'][$categoryIdent][$token]) &&
($wordCount = $words['DATA'][$categoryIdent][$token]['spamword_count'])
) {
$probability = $wordCount / $categoryData['spamcategory_words'];
} else {
$probability = $unknownProbability;
}
$scores[$categoryIdent] *= pow($probability, $tokenCount) *
pow($wordTotals / $categoryTotals, $tokenCount);
}
}
}
}
}
return $this->_rescale($scores);
} 19
function _rescale($scores) {
$total = 0.0;
$max = 0.0;
foreach ($scores as $score) {
if ($score >= $max) {
$max = $score;
}
}
foreach ($scores as $cat => $score) {
$scores[$cat] = (float) exp($score - $max);
$total += (float) pow($scores[$cat], 2);
}
$total = (float) sqrt($total);
foreach ($scores as $cat => $score) {
$scores[$cat] = (float) $scores[$cat] / $total;
}
return $scores;
}
20
Rückgabe Array
array(8) {
["spam"] => bool(false)
["scores"]=> array(2) {
["HAM"] => float(0.93491509140184)
["SPAM"] => float(0.35487148641316)
}
["stopwordcount"] => int(0)
["stopwords"] => array(0) {
}
["scoretokencount"] => int(4)
["smalltokencount"] => int(0)
["largetokencount"] => int(0)
["blocktokencount"] => int(0)
}
21
Rückgabe Elemente
• „spam“
– Einstufung mit Nutzung interner Optionswerte
• „scores“
– Prozentuale Wahrscheinlichkeit für Spam oder
Ham
– Für genaueren Zugriff z.B.
• ab 50% Spam – Forenbeitrag moderieren
• ab 80% Spam – Forenbeitrag blockieren
22
Rückgabe Zählungen
• Zusätzliche Informationen
– Stopwords
• „Zensur“
– Anteil von extrem kurzen Wörtern
• Wörtern mit Leerzeichen zwischen den Buchstaben
– Lange / überlange Wörter
• Layoutzerstörung
23
Auswertung durch Applikation
• Einfache Unterscheidung nach Spam/Ham
• Detaillierte Analyse und speziellere
Reaktion
• Reaktion ist applikationsspezifisch
– Setzen eines Flags „Freigabe erforderlich“
– Komplette Blockade des Eintrages
– Spamaufkommen zählen
– Zeitweise IP-Sperrung
– ...
24
Mögliche Erweiterung
• Mitchell
• Speicherung von Wortgruppen mit
unterschiedlichen Wertigkeiten
– Ein flinker Fuchs rennt durch die Stadt
• flinker, Fuchs, rennt, durch, Stadt => 1
• flinker Fuchs, Fuchs rennt, rennt durch => 2
• flinker Fuchs rennt, Fuchs rennt durch => 3
• Größere Datenbasis
– mehr Aufwand aber höhere Genauigkeit
25
Links
• Slides: http://thomas.weinert.info/talks
• „A Plan For Spam“
– http://www.paulgraham.com/spam.html
• B8: http://nasauber.de/programme/b8/
– PHP Implementation
26
Related docs
Get documents about "