Frage

In meinem News-Seite Projekt, ich habe eine Datenbanktabelle news mit folgenden Struktur:

 - id: [integer] unique number identifying the news entry, e.g.: *1983*
 - title: [string] title of the text, e.g.: *New Life in America No Longer Means a New Name*
 - topic: [string] category which should be chosen by the classificator, e.g: *Sports*

Darüber hinaus gibt es eine Tabelle bayes mit Informationen über Worthäufigkeiten:

 - word: [string] a word which the frequencies are given for, e.g.: *real estate*
 - topic: [string] same content as "topic" field above, e.h. *Economics*
 - count: [integer] number of occurrences of "word" in "topic" (incremented when new documents go to "topic"), e.g: *100*

Jetzt möchte ich meine PHP-Skript alle Newsbeiträge und assign eine von mehreren möglichen Kategorien (Themen), um sie zu klassifizieren.

Ist dies die richtige Implementierung? Können Sie es verbessern?

<?php
include 'mysqlLogin.php';
$get1 = "SELECT id, title FROM ".$prefix."news WHERE topic = '' LIMIT 0, 150";
$get2 = mysql_abfrage($get1);
// pTOPICS BEGIN
$pTopics1 = "SELECT topic, SUM(count) AS count FROM ".$prefix."bayes WHERE topic != '' GROUP BY topic";
$pTopics2 = mysql_abfrage($pTopics1);
$pTopics = array();
while ($pTopics3 = mysql_fetch_assoc($pTopics2)) {
    $pTopics[$pTopics3['topic']] = $pTopics3['count'];
}
// pTOPICS END
// pWORDS BEGIN
$pWords1 = "SELECT word, topic, count FROM ".$prefix."bayes";
$pWords2 = mysql_abfrage($pWords1);
$pWords = array();
while ($pWords3 = mysql_fetch_assoc($pWords2)) {
    if (!isset($pWords[$pWords3['topic']])) {
        $pWords[$pWords3['topic']] = array();
    }
    $pWords[$pWords3['topic']][$pWords3['word']] = $pWords3['count'];
}
// pWORDS END
while ($get3 = mysql_fetch_assoc($get2)) {
    $pTextInTopics = array();
    $tokens = tokenizer($get3['title']);
    foreach ($pTopics as $topic=>$documentsInTopic) {
        if (!isset($pTextInTopics[$topic])) { $pTextInTopics[$topic] = 1; }
        foreach ($tokens as $token) {
            echo '....'.$token;
            if (isset($pWords[$topic][$token])) {
                $pTextInTopics[$topic] *= $pWords[$topic][$token]/array_sum($pWords[$topic]);
            }
        }
        $pTextInTopics[$topic] *= $pTopics[$topic]/array_sum($pTopics); // #documentsInTopic / #allDocuments
    }
    asort($pTextInTopics); // pick topic with lowest value
    if ($chosenTopic = each($pTextInTopics)) {
        echo '<p>The text belongs to topic '.$chosenTopic['key'].' with a likelihood of '.$chosenTopic['value'].'</p>';
    }
}
?>

Die Ausbildung erfolgt manuell, ist es nicht in diesem Code enthält. Wenn der Text „Sie können Geld verdienen, wenn Sie Immobilien verkaufen“ in die Kategorie / Thema „Economics“ zugewiesen wird, dann werden alle Wörter (Sie können, machen sie, ...) werden in die Tabelle eingefügt bayes mit "Economics" als Thema und 1 als Standard zählen. Wenn das Wort schon gibt es in Kombination mit dem gleichen Thema wird der Zähler erhöht.

Beispiel Lerndaten:

Wort Thema Zahl

kaczynski Politik 1

Sony Technologie 1

Bank Economics 1

Telefon Technologie 1

Sony Economics 3

ericsson Technologie 2

Beispielausgabe / Ergebnis:

Titel des Textes: Telefon Test Sony Ericsson Aspen - empfindlich Winberry

Politik

.... Telefon ....Prüfung .... sony .... ericsson ....Espe ....empfindlich .... winberry

Technologie

.... Telefon GEFUNDEN ....Prüfung .... sony GEFUNDEN .... ericsson GEFUNDEN ....Espe ....empfindlich .... winberry

Wirtschaft

.... Telefon ....Prüfung .... sony GEFUNDEN .... ericsson ....Espe ....empfindlich .... winberry

Ergebnis: Der Text gehört zu Thema Technologie mit einer Wahrscheinlichkeit von ,013888888888889

Vielen Dank im Voraus!

War es hilfreich?

Lösung

Es sieht aus wie der Code korrekt ist, aber es gibt ein paar einfache Möglichkeiten, es zu optimieren. Zum Beispiel berechnen Sie p (Wort | Thema) on the fly für jedes Wort, während Sie leicht diese Werte vorher berechnen könnten. (Ich nehme an, Sie hier mehrere Dokumente klassifizieren wollen, wenn Sie nur ein einzelnes Dokument zu tun nehme ich das in Ordnung ist, da Sie berechnen es nicht für Worte in dem Dokument nicht)

In ähnlicher Weise könnte die Berechnung von p (Thema), die außerhalb der Schleife bewegt werden.

Schließlich müssen Sie nicht das gesamte Array zu sortieren, das Maximum zu finden.

Alle kleinen Punkte! Aber das ist, was Sie gefragt:)

Ich habe einige ungetestete PHP-Code zeigt, geschrieben, wie ich dieses unten implementieren würde:

<?php

// Get word counts from database
$nWordPerTopic = mystery_sql();

// Calculate p(word|topic) = nWord / sum(nWord for every word)
$nTopics = array();
$pWordPerTopic = array();
foreach($nWordPerTopic as $topic => $wordCounts)
{
    // Get total word count in topic
    $nTopic = array_sum($wordCounts);

    // Calculate p(word|topic)
    $pWordPerTopic[$topic] = array();
    foreach($wordCounts as $word => $count)
        $pWordPerTopic[$topic][$word] = $count / $nTopic;

    // Save $nTopic for next step
    $nTopics[$topic] = $nTopic;
}

// Calculate p(topic)
$nTotal = array_sum($nTopics);
$pTopics = array();
foreach($nTopics as $topic => $nTopic)
    $pTopics[$topic] = $nTopic / $nTotal;

// Classify
foreach($documents as $document)
{
    $title = $document['title'];
    $tokens = tokenizer($title);
    $pMax = -1;
    $selectedTopic = null;
    foreach($pTopics as $topic => $pTopic)
    {
        $p = $pTopic;
        foreach($tokens as $word)
        {
            if (!array_key_exists($word, $pWordPerTopic[$topic]))
                continue;
            $p *= $pWordPerTopic[$topic][$word];
        }

        if ($p > $pMax)
        {
            $selectedTopic = $topic;
            $pMax = $p;
        }
    }
} 
?>

Wie für die Mathematik ...

Sie versuchen, p zu maximieren (Thema | Wörter), finden so

arg max p(topic|words)

(IE das Argument Thema, für die p (Thema | Worte) ist die höchste)

Bayes-Theorem sagt

                  p(topic)*p(words|topic)
p(topic|words) = -------------------------
                        p(words)

So Sie suchen

         p(topic)*p(words|topic)
arg max -------------------------
               p(words)

Da p (words) ein Dokument das gleiches für jedes Thema ist, ist dies das gleiche wie die Suche nach

arg max p(topic)*p(words|topic)

Die naive Bayes-Annahme (die dies ein Bayes-Klassifikator macht) ist, dass

p(words|topic) = p(word1|topic) * p(word2|topic) * ...

diese So verwenden, müssen Sie finden

arg max p(topic) * p(word1|topic) * p(word2|topic) * ...

Wo

p(topic) = number of words in topic / number of words in total

Und

                   p(word, topic)                         1
p(word | topic) = ---------------- = p(word, topic) * ----------
                      p(topic)                         p(topic)

      number of times word occurs in topic     number of words in total
   = -------------------------------------- * --------------------------
            number of words in total           number of words in topic

      number of times word occurs in topic 
   = --------------------------------------
            number of words in topic
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top