la mise en œuvre de PHP classification Bayes: sujets Assigner aux textes
-
01-10-2019 - |
Question
Dans mes nouvelles projet de page, j'ai une table de base de données nouvelles avec la structure suivante:
- 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*
De plus, il y a une table Bayes avec des informations sur la fréquence des mots:
- 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*
Maintenant, je veux que mon script PHP pour classer toutes les entrées de nouvelles et assign une de plusieurs catégories possibles (sujets) pour eux.
Est-ce la bonne mise en œuvre? Pouvez-vous améliorer?
<?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>';
}
}
?>
La formation se fait manuellement, il ne figure pas dans ce code. Si le texte « Vous pouvez gagner de l'argent si vous vendez des biens immobiliers » est attribué à la catégorie / thème « économie », puis tous les mots (vous, peut, faire, ...) sont insérés dans la table Bayes avec "l'économie" comme sujet et 1 nombre standard. Si le mot est déjà là en combinaison avec le même sujet, le compte est incrémenté.
données d'apprentissage Exemple:
countmot sujet
kaczynski Politique 1
Sony Technologie 1
Economie banque 1
téléphone Technologie 1
Sony Economie 3
ericsson Technologie 2
Exemple de sortie / résultats:
Titre du texte: test Téléphone Sony Ericsson Aspen - sensible Winberry
La politique
.... téléphone ....tester .... sony .... ericsson ....tremble ....sensible .... Winberry
Technologie
.... téléphone TROUVE ....tester .... sony TROUVE .... TROUVE ericsson ....tremble ....sensible .... Winberry
Economie
.... téléphone ....tester .... sony TROUVE .... ericsson ....tremble ....sensible .... Winberry
Résultat: Le texte appartient au sujet de la technologie avec un risque de ,013888888888889
Merci beaucoup à l'avance!
La solution
Il semble que votre code est correct, mais il y a quelques moyens faciles à optimiser. Par exemple, calculer p (mot | sujet) à la volée pour chaque mot pendant que vous pouvez facilement calculer ces valeurs à l'avance. (Je suppose que vous voulez classer plusieurs documents ici, si vous faites un seul document que je suppose que cela est correct puisque vous ne calculez pas les mots ne sont pas dans le document)
De même, le calcul de p (le sujet) peut être déplacé en dehors de la boucle.
Enfin, vous n'avez pas besoin de trier le tableau entier pour trouver le maximum.
Tous les petits points! Mais c'est ce que vous avez demandé:)
J'ai écrit quelques montrant PHP-code non testé comment je mettre en œuvre ce ci-dessous:
<?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;
}
}
}
?>
En ce qui concerne les mathématiques ...
Vous essayez de maximiser p (sujet | mots), afin de trouver
arg max p(topic|words)
(IE le sujet d'argument pour lequel p (sujet | mots) est le plus élevé)
théorème de Bayes dit
p(topic)*p(words|topic)
p(topic|words) = -------------------------
p(words)
Vous cherchez
p(topic)*p(words|topic)
arg max -------------------------
p(words)
Comme p (mots) d'un document est le même pour tout sujet c'est le même que la recherche
arg max p(topic)*p(words|topic)
L'hypothèse de Bayes naïf (ce qui en fait un classifieur de Bayes naïf) est que
p(words|topic) = p(word1|topic) * p(word2|topic) * ...
Donc, en utilisant cela, vous devez trouver
arg max p(topic) * p(word1|topic) * p(word2|topic) * ...
Où
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