Bayesscher Spam-Filter (Bayesian spam filter)

Document Sample
scope of work template
							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