Похоже, ваш код правильный, но есть несколько простых способов его оптимизировать. Например, вы вычисляете p (слово | тема) на лету для каждого слова, в то время как вы можете легко вычислить эти значения заранее. (Я предполагаю, что вы хотите классифицировать несколько документов здесь, если вы делаете только один документ, я думаю, что это нормально, поскольку вы не рассчитываете его для слов, которых нет в документе)
Аналогично, вычисление 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 (topic | words) является самой высокой)
Теорема Байеса гласит
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)
Наивное предположение Байеса (что делает этот классификатор наивным Байеса) следующим:
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