Вопрос

В моем проекте страницы новостей у меня есть таблица базы данных Новости со следующей структурой:

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

Кроме того, есть стол байс С информацией о частотах слово:

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

Теперь я хочу, чтобы мой PHP-скрипт классифицирует все новости и назначить одну из нескольких возможных категорий (темы) для них.

Это правильная реализация? Можете ли вы улучшить это?

<?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>';
    }
}
?>

Обучение осуществляется вручную, он не включен в этот код. Если текст «вы можете зарабатывать деньги, если вы продаете недвижимость», присвоен категории / тему «Экономика», то все слова (вы, можете, сделать, ...) вставляются в таблицу байс с «экономикой» как тема и 1 как стандартный счет. Если слово уже в сочетании с той же темой, подсчет увеличивается.

Образец данных обучения:

Слово тема подсчет

Kaczynski Politics 1.

Технология Sony 1.

экономика банка 1

Телефонная технология 1.

Sony Economics 3.

Технология Ericsson 2.

Образец вывода / результата:

Название текста: Телефон Телефон Sony Ericsson Aspen - Чувствительный уклон

Политика

.... Телефон .... Тест .... Sony .... Ericsson .... aspen .... чувствительный .... уход

Технология

.... Телефон нашел .... Тест .... Sony обнаружил ... Эрикссон нашел .... Аспен .... чувствительный .... уход

Экономика

.... Телефон .... Тест .... Sony обнаружил .... Ericsson .... Аспен .... чувствительный .... уход

Результат: текст принадлежит тематическим технологиям с вероятностью 0,0138888888888889

Заранее большое спасибо!

Это было полезно?

Решение

Похоже, ваш код правильный, но есть несколько простых способов оптимизации его. Например, вы рассчитываете P (Word | topic) на лету для каждого слова, когда вы можете легко рассчитать эти значения заранее. (Я предполагаю, что вы хотите классифицировать несколько документов здесь, если вы делаете только один документ, я полагаю, это нормально, так как вы не рассчитываете его для слов, а не в документе)

Аналогичным образом, расчет P (тема) может быть перемещен за пределы петли.

Наконец, вам не нужно отсортировать весь массив, чтобы найти максимум.

Все маленькие очки! Но это то, что вы просили :)

Я написал несколько непроверенных PHP-кода, показывающий, как я реализую это ниже:

<?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;
        }
    }
} 
?>

Что касается математики ...

Вы пытаетесь максимизировать P (тема | слова), так найти

arg max p(topic|words)

(То есть тема аргумента, для которой p (тема | слова) - самая высокая)

Бэйс Теорема говорит

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

Так что вы ищете

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

Поскольку p (слова) документа одинаковы для любой темы, это то же самое, что нахождение

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

Предположение Naive Bayes (что делает это на Naive Bayes Classifier), это то, что

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

Итак, используя это, вам нужно найти

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

Где

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

А также

                   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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top