> copix > Charts > Presentation > Tutoriaux > Documentation > Bayes
fr

Présentation

Les réseaux bayesiens sont aujourd'hui très prisés par beaucoup de projets. Savoir si un élément est du spam, retrouver la langue d'un texte, connaitre le taux de chance que certains symptômes définissent une maladie... il existe un nombre incalculable d'utilisations du théorème de Bayes.

L'intérêt du théorème de Bayes est - non pas de trouver une probabilité de trouver un élément dans un jeu de données - mais de savoir quel catégorie de données offre le plus de chances de tomber sur notre élément. Nous fonctionnons "à postériori" c'est à dire "après coup".

Nous allons vous présenter le fonctionnement du théorème avec un exemple connu, puis nous le développerons avec la classe fournie avec Copix: BayesFactory (dans le package "tools", module "bayes").

Bayes ? Thomas Bayes

Thomas Bayes était un pasteur britannique, et mathématicien né en 1702 à Londres - mort le 17 avril 1761. Probabiliste de renommé, il découvrit le théorème de "probabilité à postériori" à titre posthume en 1764. Ce sont en fait ces études qui ont amené au théorème qu'il découvrit durant ses recherches.

Le théorème de Bayes s'inscrit dans son essai: "Essais sur la manière de résoudre un problème dans la doctrine des risques (Essay Towards Solving a Problem in the Doctrine of Chances - 1763)" publié à titre posthume. (source wikipedia).

Définition du théorème par l'Exemple

Cet exemple avec, un E majuscule, va vous faire découvrir l'intérêt de ce théorème, nous étudierons un autre exemple plus complexe mais plus évident quant aux résultats par la suite.

Cet exemple est simple mais démontre la différence de résultat entre la probabilité de tirage, et la probabilité de source à postériori. Cet l'exemple le plus répandu du théorème de Bayes et il permet de poser le problème, de définir ce que nous cherchons, et la solution.

Nous allons imaginer un jeu de test: 2 sacs qui contiennent des boules blanches et noires.

Nous n'avons donc pas autant de chance de trouver une boule blanche qu'un boule noire.
Si nous tirons dans le premier sac, nous avons 75% de chance de trouver une boule blanche.
Si nous tirons dans le second sac, nous avons 50% de chance de trouver une boule blanche.

Maintenant, nous nous bandons les yeux, nous piochons au hasard une boule sans savoir dans quel sac nous piochons... nous regardons ensuite la couleur de la boule et c'est une boule blanche.

Alors à votre avis, quel est la chance que cette boule provienne du sac 1 ? ou du sac 2?

La probabilité simpliste nous dit que nous avons: ( 50% + 75% ) / 2 = 62.5% de chance de trouver une boule blanche mais pas quelle est la chance que ce soit depuis le sac 1.

Là où le théorème de Bayes va entrer en jeu, c'est justement après le tirage... à posteriori si nous avons tiré une blanche, quel est la chance que je l'ai tiré du sac 1 ou du sac 2 ? Cette question est certainement anodine, mais si vous répondez "62.5% de chance de la tiré du sac 1" vous avez faux. Vous allez voir.

Voici le théorème de Bayes sous sa forme simple et développée (plus intéressante pour la suite) que nous allons utiliser. Je ne suis pas probabiliste, je vous assure que cette formule est simple à lire. Laissez moi vous expliquer:

Je traduis:

Ce qui nous donne: P(B|A) = ( 50% * 75%) / (50%*75% + 50%*50%) = 0.6 ⇒ 60%
ou en forme simple:
P(B|A) = ( 50*75%) / (62.5) = 0.6 ⇒ 60%\

Ce qu'il faut comprendre, c'est que "après coup", après avoir tiré au hasard une boule blanche, nous savons que nous avons 60% de chance qu'elle provienne du sac 1.

L'exemple qui va suivre est plus complexe mais mets en évidence l'importance de l'utilisation avancée du théorème de Bayes.

La différence entre la forme simple et la forme développée ?

La forme simple estime que vous ayez autant de chance de vous trouver dans n'importe quelle catégorie. Notre exemple de boules blanches et noires est un cas typique. Effectivement, nous n'avons pas plus de chance de piocher dans le sac 1 que le sac 2.

La forme simple peut donc convenir. Mais le soucis se pose dans le cas ou nous devons nous pencher sur l'évidence du tirage. Le cas suivant demande l'utilisation de la forme développé puisque nous n'aurons pas autant de chance de trouver un pourriel qu'un message sain.

Un autre fonctionnement qu'il faut prendre en compte, c'est l'exemple de la détection de langue dans des textes classés. Si par exemple nous classions des textes anglais et français puis que nous désirions tester la langue d'un nouveau texte, il faudra estimer que nous avons autant de chance que le texte soit anglais ou français. Or, nous n'aurons pas forcément autant de texte anglais dans la base de données que de texte français.

A ce moment, la forme simple est préconisée puisque l'évidence du tirage n'est pas à prendre en compte !

Notez bien que vous pourrez utiliser la classe Bayes de Copix pour les deux manières de calculer.

Spam ou non-spam ?

Nous allons voir un cas typique du théorème de Bayes, utilisé en partie par Spamassassin. Cette utilisation du théorème va s'avérer extrêmement fiable si nous avons un grand jeu de données.

Partons du principe que nous avons 100 messages dont 10 sont classés en "pourriel" et 90 en "ok". Nous allons pouvoir traiter nos nouveaux messages entrant en analysant le contenu.

Sans nous baser sur un ensemble de mots clefs, en classant nos éléments, le théorème de Bayes va vous donner une estimation du risque que votre message soit à classer en pourriel.

Notre nouveau message contient 60% de mots que nous trouvons dans les spams, mais 80% de mots dans "ok". Cela signifie que nous avons des mots qui se trouvent dans les deux catégories. Notre logique humaine nous permettra de savoir si le message est un spam ou non, selon le sens... mais l'ordinateur ne saura pas le faire. De plus, nous voyons bien que nous n'avons que 10% de pourriel... nous n'avons donc pas autant de chance de tomber sur un spam qu'un message sain.

Par contre, grâce au théorème de Bayes, il est fort possible de connaitre le risque en connaissant, à postériori, la probabilité que ce message puisse se trouver dans la catégorie "pourriel"

Définissons nos données:

Appliquons le théorème:
P(pourriel|message) = ( P(pourriel) P(message|pourriel) ) / ( P(pourriel)P(message|pourriel) + P(ok)|P(message|ok) )
soit:
P(pourriel|message) = ( 10 * 60) / (10*60 + 90*80)
P(pourriel|message) ≅ .07692
soit environ 7.692% de chance que notre message soit un spam.

Maintenant, imaginez que notre boite soit très spamée. Par exemple 50% de message pourriels, et donc 50% de message sains. Le calcul donnerait:
(50 * 60 ) /(50 *60 + 50*80) ≅ .4285714285
soit 42% de chance que le message arrivé soit un spam.

C'est bel et bien sur l'évidence des données que se base le théorème de Bayes.

C'est donc comme cela que nous aurons tout du moins une bonne estimation pour classer nos messages. De plus, en classant ce message en non-spam ou en spam va accroitre la base de connaissances utilisée par notre théorème. De ce fait, plus vous classez vos éléments, plus l'analyse sera fine et fiable.

C'est d'ailleurs pour cela que la plupart des systèmes utilisant un réseau Bayésien vous demande d'effectuer un classement manuel pendant quelques jours afin d'affiner la recherche.

Maintenant que nous avons vu comment fonctionne le théorème, il ne reste plus qu'à se simplifier la vie avec la classe Bayes.

Utilisation de la classe

Principe de base

La création d'une interface de calcul Bayesien se fait depuis la factory BayesFactory contenu dans le module "bayes":


//mode statique
$b = _ioClass('bayes|bayesfactory')->create();
//correspond par défaut à
$b = _ioClass('bayes|bayesfactory')->create(BayesFactory::STATIC_DATAMODE);

//stoquer le dataset en base de données:
$b = _ioClass('bayes|bayesfactory')->create(BayesFactory::DB_DATAMODE,"nom_du_dataset");
 

Comme vous pouvez le voir cette classe fonctionne en mode "static" ou "db". En mode "db" les données sont enregistrée en base de données. En mode "static", tout se passe en mémoire. Le mode par défaut est le mode "static".

En mode "DB", vous devez spécifier un nom de "dataset", c'est en fait le nom de votre classement de données. Par exemple si vous voulez gérer du spam pour le module "wiki", donner le nom de dataset: "wiki_spamcheck". Le nom est complètement arbitraire.

Si le dataset existe en base, il sera alors utilisé et complété lors des appels à getProba(), getBayes(), train() et untrain().

Afin de respecter les notations probabilistes, getProba(A,B) correspondant à P(A|B) demandera en premier argument la valeur à tester, alors que getBayes(B,A) correspondant à P(B|A) prend en premier argument la catégorie.

Entrer des données

La méthode pour faire un apprentissage ne nomme "train". Deux arguments son nécessaires: le nom de la catégorie, et les termes à y insérer.

Exemple d'apprentissage de langue:



$b = _ioClass('bayes|bayesfactory')->create();
$b->train('fr','Ceci est une phrase en français');
$b->train('fr','Encore une phrase dans la langue de Molière');

$b->train('en','This is an english sentence');
$b->train('en','Once again a sentence in Shakespear language');

 

Ici, deux catégories seront enregistrées: "en" et "fr".

Connaitre la valeur Bayesienne

La métode à utiliser est "getBayes" qui prend en argument le jeux à tester, et la catégorie.



$b = _ioClass('bayes|bayesfactory')->create();
$b->train('fr','Ceci est une phrase en français');
$b->train('fr','Encore une phrase dans la langue de Molière');

$b->train('en','This is an english sentence');
$b->train('en','Once again a sentence in Shakespear language');

//$val contient la valeur en pourcentage de chance que la phrase soit en français
$val = $b->getBayes('fr','cette phrase est-elle française ?');

 

Par défaut, c'est la forme développée qui est utilisée. Pour utiliser le calcul "simple"" qui ne prend pas en compte les évidences, il faut assigner le troisième paramètre à "true":


$val = $b->getBayes('fr','cette phrase est-elle française ?',true);
 

$val sera alors calculé en estimant que vous aviez autant de phrases anglaises que françaises dans vos catégories. Cela peut en effet être plus proche de vos besoins. Il est parfois peut évident d'avoir exactement le même nombre de mots anglais que français dans un jeu de données. De ce fait, vous risquez d'avoir des probabilités peut évidentes. Cela dit, l'évidence peut aussi être un facteur important. Si vous voulez prendre en compte qu'il y a peu de chance d'avoir un texte anglais dans vos données, le mode "simple" va vous donner un mauvais résultat. Dans ce cas précis, vous voulez aussi jouer avec l'évidence de probabilité de chance, vous ne devriez pas utiliser le mode simple dit "naïf".

Connaitre la valeur de probabilité simple

Vous pouvez connaitre la valeur de probabilité simple en appelant getProba(). Cette méthode demande en argument le nom de la catégorie et le jeu à tester:



$b = _ioClass('bayes|bayesfactory')->create();
$b->train('fr','Ceci est une phrase en français');
$b->train('fr','Encore une phrase dans la langue de Molière');

$b->train('en','This is an english sentence');
$b->train('en','Once again a sentence in Shakespear language');

//$val contient la valeur en pourcentage de mots en français trouvés dans la phrase
$val = $b->getProba('cette phrase est-elle française ?','fr');
 

Exemple d'utilisation avec les boules blanches et noires

Ici est présenté l'exemple expliqué en haut de cet article. Nous allons voir et vérifier que la classe Bayes retourne le résultat attendu.

Bien entendu, je vous laisse créer votre module pour tester, ici je ne vous présenterai que le code à prévoir pour l'actiongroup.


class ActionGroupDefault extends CopixActionGroup {

    function processDefault (){
        $b = _ioClass('bayes|bayesfactory')->create();
               
        //1er sac: 30 boules blanches, 10 boules noires
        $j=0;
        for ($i=0;$i<40;$i++){
                if($j<30){
                        $bayes->train("sac1","blanche");
                        $j++;
                }
                else{
                        $bayes->train("sac1","noire");
                }
        }
        //2eme sac: 20 boules blanches, 20 boules noires
        $j=0;
        for ($i=0;$i<40;$i++){
                if($j<20){
                        $bayes->train("sac2","blanche");
                        $j++;
                }
                else{
                        $bayes->train("sac2","noire");
                }
        }
       
        $ppo = new CopixPPO();
        $ppo->MAIN = "Valeur Bayesienne pour que la boule blanche provienne du sac 1: <br />";
        $ppo->MAIN .= $bayes->getBayes('sac1','blanche')."%";
        return _arDirectPPO($ppo,"generictools|blank.tpl"); //affichera 60% dans une page blanche
    }

}

 

Ce test est très connu et peut vous donner un bon exemple de ce que permet le calcul bayesien.

A venir

Vous pouvez tester à peu près ce que vous voulez à condition de mettre un maximum de données pour un traitement fin. Sachez que nous travaillons pour utiliser cette classe dans le moteur de recherche, le traitement des spam du module blog (à venir) et le test de protection de doublon de rapport de bug dans le futur module "bugtrax".

J'espère que cette classe vous permettra de vous faciliter la vie dans votre analyse de recherche de données. Je serai très content de connaître quelles applications vous avez voué à cette classe. Les commentaires de pages vous attendent :)