Implémenter Naive Bayes dans Python 3.3

** Ceci est l'article du premier jour de Real Escape Advent Calendar 2013 **

Commençons par l'apprentissage automatique Implémentons le 3ème filtre basilien Implémentation des baies naïves introduites dans.

Cependant, le code de cet article est un peu déroutant. Plus précisément, il existe de nombreux pièges, tels que le nom de la variable est un mot singulier appelé mot, mais le type est liste. De plus, j'ai trouvé une erreur courante dans la Liste 7 à la page 3 que l'opérateur de comparaison s'est trompé. C'était. Peut-être que vous n'exécutez pas le code vous-même.

Donc, le filtre basilien introduit dans cet article

--En Python 3.3 --Utilisation de MeCab au lieu de l'analyse morphologique japonaise de Yahoo! Developers Network --Plus lisible

Réimplémenté.

Postscript

À l'aide du filtre Basian créé dans cet article, nous avons appris et classé à l'aide de la page Web acquise à l'aide de l'API Bing. http://qiita.com/katryo/items/62291ba328de9d12bd30

code

naive_bayes.py


#coding:utf-8
# http://gihyo.jp/dev/serial/01/machine-learning/Python3 avec l'implémentation du filtre basilien de 0003.Amélioré pour être lisible pendant 3
import math
import sys
import MeCab


class NaiveBayes():
    def __init__(self):
        self.vocabularies = set()
        self.word_count = {}  # {'Mesures contre la pollinose': {'Pollen Sugi': 4, 'médicament': 2,...} }
        self.category_count = {}  # {'Mesures contre la pollinose': 16, ...}

    def to_words(self, sentence):
        """
contribution: 'Tout à moi'
production: tuple(['tout', 'moi même', 'de', 'Comment', 'Quoi'])
        """
        tagger = MeCab.Tagger('mecabrc')  #Vous pouvez utiliser un autre Tagger
        mecab_result = tagger.parse(sentence)
        info_of_words = mecab_result.split('\n')
        words = []
        for info in info_of_words:
            #Si vous divisez par macab, "" est à la fin de la phrase, avant cela'EOS'Arrive
            if info == 'EOS' or info == '':
                break
                # info => 'Nana\t assistant,Aide finale,*,*,*,*,Nana,N / a,N / a'
            info_elems = info.split(',')
            #Sixièmement, il y a des mots qui ne sont pas utilisés. Si le sixième est'*'Si tel est le cas, entrez le 0e
            if info_elems[6] == '*':
                # info_elems[0] => 'Van Rossam\t substantif'
                words.append(info_elems[0][:-3])
                continue
            words.append(info_elems[6])
        return tuple(words)

    def word_count_up(self, word, category):
        self.word_count.setdefault(category, {})
        self.word_count[category].setdefault(word, 0)
        self.word_count[category][word] += 1
        self.vocabularies.add(word)

    def category_count_up(self, category):
        self.category_count.setdefault(category, 0)
        self.category_count[category] += 1

    def train(self, doc, category):
        words = self.to_words(doc)
        for word in words:
            self.word_count_up(word, category)
        self.category_count_up(category)

    def prior_prob(self, category):
        num_of_categories = sum(self.category_count.values())
        num_of_docs_of_the_category = self.category_count[category]
        return num_of_docs_of_the_category / num_of_categories

    def num_of_appearance(self, word, category):
        if word in self.word_count[category]:
            return self.word_count[category][word]
        return 0

    def word_prob(self, word, category):
        #Calcul de la loi bayésienne. Généralement une fraction très proche de zéro.
        numerator = self.num_of_appearance(word, category) + 1  # +1 est la méthode de Laplace de lissage additif
        denominator = sum(self.word_count[category].values()) + len(self.vocabularies)

        #Dans Python3, la division est automatiquement flottante
        prob = numerator / denominator
        return prob

    def score(self, words, category):
        #C'est un mot pour prendre le journal_prob vaut 0.000....Parce que cela devient un petit nombre d'environ 01
        score = math.log(self.prior_prob(category))
        for word in words:
            score += math.log(self.word_prob(word, category))
        return score

    #Si vous ne vous connectez pas, la valeur est peut-être trop petite et insuffisante.
    def score_without_log(self, words, category):
        score = self.prior_prob(category)
        for word in words:
            score *= self.word_prob(word, category)
        return score

    def classify(self, doc):
        best_guessed_category = None
        max_prob_before = -sys.maxsize
        words = self.to_words(doc)

        for category in self.category_count.keys():
            prob = self.score(words, category)
            if prob > max_prob_before:
                max_prob_before = prob
                best_guessed_category = category
        return best_guessed_category

if __name__ == '__main__':
    nb = NaiveBayes()
    nb.train('''Python est un langage de programmation open source créé par le Néerlandais Guido Van Rossam.
C'est un type de langage de script orienté objet et est largement utilisé en Europe et aux États-Unis avec Perl. Nommé d'après la comédie "Flying Monty Python" produite par la chaîne de télévision britannique BBC.
Python signifie reptile Nishiki snake en anglais et est parfois utilisé comme mascotte ou icône dans le langage Python. Python est un langage de haut niveau à usage général. Conçu avec un accent sur la productivité du programmeur et la fiabilité du code, il dispose d'une grande bibliothèque standard pratique avec une syntaxe et une sémantique de base minimales.
Il prend en charge les opérations de chaîne en utilisant Unicode, et le traitement japonais est également possible en standard. Il prend en charge de nombreuses plates-formes (plates-formes de travail), et dispose de documents abondants et de bibliothèques abondantes, de sorte que son utilisation augmente dans l'industrie.
             ''',
             'Python')
    nb.train('''Serpent (serpent) est un terme général pour les reptiles qui sont classés dans l'ordre Serpentes.
Il se caractérise par son corps élancé et sans membres. Cependant, des animaux de forme similaire existent également dans d'autres groupes.
                ''', 'Snake')
    nb.train('''Ruby est un langage de script orienté objet développé par Yukihiro Matsumoto (communément appelé Matz).
Réalise la programmation orientée objet dans les domaines où les langages de script tels que Perl ont été traditionnellement utilisés.
Ruby est né le 24 février 1993 et a été annoncé le fj en décembre 1995.
Le nom Ruby est dû au fait que le langage de programmation Perl prononce la même chose que Pearl, la pierre de naissance de juin.
Il a été nommé d'après le rubis de la pierre de naissance du collègue de Matsumoto (juillet).
             ''',
             'Ruby')
    nb.train('''Ruby (anglais:Ruby, Kodama) est une variante du Corindon (bille d'acier). C'est un bijou avec une couleur rouge caractéristique.
Les rubis naturels sont produits en Asie et ne peuvent être obtenus en Europe et aux États-Unis.
Même dans la zone de production, les endroits où les belles pierres pouvant être utilisées comme bijoux peuvent être obtenues sont extrêmement limités.
Les grosses pierres de plus de 3 carats ont également un faible rendement.
             ''', 'Gem')
    doc = 'Open source réalisé par Guido Van Rossam'
    print('%s =>Catégorie estimée: %s' % (doc, nb.classify(doc)))  #Catégorie estimée:Devrait être Python
    print('Probabilité d'être dans la catégorie Python: %s' % nb.score_without_log(['Guido Van Rossam', 'Mais', 'Avait fait'], 'Python'))
    print('Probabilité d'être dans la catégorie Ruby: %s' % nb.score_without_log(['Guido Van Rossam', 'Mais', 'Avait fait'], 'Ruby'))

    doc = 'Le langage de programmation Ruby est un pur langage orienté objet.'
    print('%s =>Catégorie estimée: %s' % (doc, nb.classify(doc)))  #Catégorie estimée:Devrait être Ruby
    print('Probabilité d'être dans la catégorie Ruby: %s' % nb.score_without_log(['Langage de programmation', 'de', 'Ruby', 'Est', 'pur', 'Nana', 'Langage orienté objet', 'est', '。'], 'Ruby'))
    print('Probabilité d'être dans la catégorie Python: %s' % nb.score_without_log(['Langage de programmation', 'de', 'Ruby', 'Est', 'pur', 'Nana', 'Langage orienté objet', 'est', '。'], 'Python'))

    doc = 'corindon'
    print('%s =>Catégorie estimée: %s' % (doc, nb.classify(doc)))  #Catégorie estimée:Devrait être un bijou
    print('Probabilité d'être dans la catégorie Gem: %s' % nb.score_without_log(['corindon'], 'Gem'))
    print('Probabilité d'être dans la catégorie Ruby: %s' % nb.score_without_log(['corindon'], 'Ruby'))

Votre propre commentaire

Nous expliquerons ce que fait ce code, le divisant en formation et le classer.

Ce que vous faites en formation

La méthode train (self, doc, category) de NaiveBayes entre la chaîne doc et la catégorie à laquelle appartient la chaîne, et place le document avec ce mot dans cette catégorie dans l'objet NaiveBayes. "Devrais-je?"

Ce qui suit est un résumé.

  1. Décomposez la chaîne d'entrée en une liste de mots avec MeCab ** to_words () **
  2. Comptez le nombre de fois où chaque mot apparaît. ** word_count_up () **
  3. Comptez le nombre de fois où la catégorie saisie a été saisie ** category_count_up () **

Ce que vous faites avec classifier

Parmi les catégories saisies jusqu'à présent dans la phase d'apprentissage, «Quelle est la plus plausible pour inclure le texte saisi?» Est calculée.

En d'autres termes, la méthode du score est utilisée pour chaque catégorie pour calculer la probabilité (le log est pris pour faciliter le calcul).

Celle avec le score le plus élevé parmi toutes les catégories est considérée comme la catégorie avec la probabilité la plus élevée, et cette catégorie est finalement sortie. A ce moment, la méthode de Laplace de lissage par addition est utilisée.

À propos de l'utilisation de log dans NaiveBayes.score

Pourquoi utilisez-vous log dans la fonction score et calculez-vous la probabilité calculée avec prior_prob et word_prob de manière logarithmique?

Comme indiqué dans Article original de la revue technique, la probabilité calculée par la formule de la loi de Bayes La valeur de est très proche de 0. Le nombre total de mots qui apparaissent dans un document est énorme, et le nombre de fois qu'un mot particulier (tel que "Python", "pur" ou "fait") apparaît est très petit en comparaison. Par conséquent, le logarithme est pris avec e afin qu'il puisse être calculé même s'il est proche de 0.

Alors que faire si nous calculons cette probabilité sans journalisation? Essayons.

    def score(self, words, category):
        #C'est un mot pour prendre le journal_prob vaut 0.000....Parce que cela devient un petit nombre d'environ 01
        score = math.log(self.prior_prob(category))
        for word in words:
            score += math.log(self.word_prob(word, category))
        return score

    #Si vous ne vous connectez pas, la valeur est peut-être trop petite et insuffisante.
    def score_without_log(self, words, category):
        score = self.prior_prob(category)
        for word in words:
            score *= self.word_prob(word, category)
        return score

score_without_log est une version qui calcule la probabilité sans prendre le logarithmique. Prendre le logarithme de a * b * c donne log (a) + log (b) + log (c). Dans la méthode de score, le résultat du calcul de word_prob a été ajouté à plusieurs reprises pour marquer dans la boucle pour mot dans les mots, mais dans la méthode score_without_log, il est multiplié à plusieurs reprises.

Si vous exécutez le code dans naive_bayes.py tel quel, vous pouvez voir l'effet de la journalisation.

À propos, cette partie du code forme quatre catégories de "Python, Snake, Gem, Ruby".

naive_bayes.py


if __name__ == '__main__':
    nb = NaiveBayes()
    nb.train('''Python est un langage de programmation open source créé par le Néerlandais Guido Van Rossam.
C'est un type de langage de script orienté objet et est largement utilisé en Europe et aux États-Unis avec Perl. Nommé d'après la comédie "Flying Monty Python" produite par la chaîne de télévision britannique BBC.
Python signifie reptile Nishiki snake en anglais et est parfois utilisé comme mascotte ou icône dans le langage Python. Python est un langage de haut niveau à usage général. Conçu avec un accent sur la productivité du programmeur et la fiabilité du code, il dispose d'une grande bibliothèque standard pratique avec une syntaxe et une sémantique de base minimales.
Il prend en charge les opérations de chaîne en utilisant Unicode, et le traitement japonais est également possible en standard. Il prend en charge de nombreuses plates-formes (plates-formes de travail), et dispose de documents abondants et de bibliothèques abondantes, de sorte que son utilisation augmente dans l'industrie.
             ''',
             'Python')
    nb.train('''Serpent (serpent) est un terme général pour les reptiles qui sont classés dans l'ordre Serpentes.
Il se caractérise par son corps élancé et sans membres. Cependant, des animaux de forme similaire existent également dans d'autres groupes.
                ''', 'Snake')
    nb.train('''Ruby est un langage de script orienté objet développé par Yukihiro Matsumoto (communément appelé Matz).
Réalise la programmation orientée objet dans les domaines où les langages de script tels que Perl ont été traditionnellement utilisés.
Ruby est né le 24 février 1993 et a été annoncé le fj en décembre 1995.
Le nom Ruby est dû au fait que le langage de programmation Perl prononce la même chose que Pearl, la pierre de naissance de juin.
Il a été nommé d'après le rubis de la pierre de naissance du collègue de Matsumoto (juillet).
             ''',
             'Ruby')
    nb.train('''Ruby (anglais:Ruby, Kodama) est une variante du Corindon (bille d'acier). C'est un bijou avec une couleur rouge caractéristique.
Les rubis naturels sont produits en Asie et ne peuvent être obtenus en Europe et aux États-Unis.
Même dans la zone de production, les endroits où les belles pierres pouvant être utilisées comme bijoux peuvent être obtenues sont extrêmement limités.
Les grosses pierres de plus de 3 carats ont également un faible rendement.
             ''', 'Gem')
    doc = 'Open source réalisé par Guido Van Rossam'
    print('%s =>Catégorie estimée: %s' % (doc, nb.classify(doc)))  #Catégorie estimée:Devrait être Python
    print('Probabilité d'être dans la catégorie Python: %s' % nb.score_without_log(['Guido Van Rossam', 'Mais', 'Avait fait'], 'Python'))
    print('Probabilité d'être dans la catégorie Ruby: %s' % nb.score_without_log(['Guido Van Rossam', 'Mais', 'Avait fait'], 'Ruby'))

    doc = 'Le langage de programmation Ruby est un pur langage orienté objet.'
    print('%s =>Catégorie estimée: %s' % (doc, nb.classify(doc)))  #Catégorie estimée:Devrait être Ruby
    print('Probabilité d'être dans la catégorie Ruby: %s' % nb.score_without_log(['Langage de programmation', 'de', 'Ruby', 'Est', 'pur', 'Nana', 'Langage orienté objet', 'est', '。'], 'Ruby'))
    print('Probabilité d'être dans la catégorie Python: %s' % nb.score_without_log(['Langage de programmation', 'de', 'Ruby', 'Est', 'pur', 'Nana', 'Langage orienté objet', 'est', '。'], 'Python'))

    doc = 'corindon'
    print('%s =>Catégorie estimée: %s' % (doc, nb.classify(doc)))  #Catégorie estimée:Devrait être un bijou
    print('Probabilité d'être dans la catégorie Gem: %s' % nb.score_without_log(['corindon'], 'Gem'))
    print('Probabilité d'être dans la catégorie Ruby: %s' % nb.score_without_log(['corindon'], 'Ruby'))

C'est le résultat de l'exécution.

Open source réalisé par Guido Van Rossam=>Catégorie estimée: Python
Probabilité d'être dans la catégorie Python: 5.05740150710565e-08
Probabilité d'être dans la catégorie Ruby: 2.592066486298008e-08
Le langage de programmation Ruby est un pur langage orienté objet. =>Catégorie estimée: Ruby
Probabilité d'être dans la catégorie Ruby: 1.0568043348436783e-20
Probabilité d'être dans la catégorie Python: 1.4013428667584096e-21
corindon=>Catégorie estimée: Gem
Probabilité d'être dans la catégorie Gem: 0.0018248175182481751
Probabilité d'être dans la catégorie Ruby: 0.0008143322475570033

** 1.0568043348436783e-20 ** …… (゚ Д ゚;)

10 moins 20 puissance. C'est un nombre très proche de 0.

Plus la chaîne d'entrée est longue, moins elle est susceptible de tomber dans une catégorie particulière. Au contraire, le dernier exemple consiste à raccourcir la chaîne de caractères d'entrée et à calculer la probabilité d'entrer dans une catégorie spécifique uniquement par "corindon". Mais quand même, la probabilité d'être dans la catégorie la plus probable «Gem» n'est que de ** 0,0018248175182481751 **. 0,18%. C'est beaucoup plus grand que la probabilité de 0,0008143322475570033 d'être dans la catégorie "Ruby", mais c'est encore très petit. Vous pouvez voir que c'est un nombre difficile à calculer.

référence

Article japonais sur Naive Bays http://aidiary.hatenablog.com/entry/20100613/1276389337

Postscript

À l'aide du filtre Basian créé dans cet article, nous avons appris et classé à l'aide de la page Web acquise à l'aide de l'API Bing. Cliquez ici pour la suite http://qiita.com/katryo/items/62291ba328de9d12bd30

Recommended Posts

Implémenter Naive Bayes dans Python 3.3
Mettre en œuvre des recommandations en Python
Implémenter XENO avec python
Implémenter sum en Python
Implémenter Traceroute dans Python 3
Implémenter d'anciens chiffrements en python
Implémenter Redis Mutex en Python
Implémenter l'extension en Python
Mettre en œuvre un RPC rapide en Python
Implémenter l'algorithme de Dijkstra en python
Implémenter le bot de discussion Slack en Python
Mettre en œuvre l'apprentissage de l'empilement en Python [Kaggle]
Implémenter la fonction power.prop.test de R en python
Implémenter le modèle Singleton en Python
Implémentez rapidement l'API REST en Python
Quadtree en Python --2
Python en optimisation
CURL en Python
J'ai essayé d'implémenter PLSA en Python
Métaprogrammation avec Python
Python 3.3 avec Anaconda
Géocodage en python
SendKeys en Python
Implémenter __eq__ etc. de manière générique dans la classe Python
Méta-analyse en Python
Unittest en Python
Implémenter le filtre FIR en langage Python et C
Mettre en œuvre collectivement des tests d'hypothèses statistiques en Python
J'ai essayé d'implémenter PLSA dans Python 2
Époque en Python
Discord en Python
Allemand en Python
DCI en Python
tri rapide en python
nCr en python
N-Gram en Python
Programmation avec Python
Plink en Python
J'ai essayé d'implémenter ADALINE en Python
Constante en Python
J'ai essayé d'implémenter PPO en Python
FizzBuzz en Python
Sqlite en Python
Étape AIC en Python
LINE-Bot [0] en Python
CSV en Python
Assemblage inversé avec Python
Réflexion en Python
Constante en Python
nCr en Python.
format en python
Scons en Python 3
Puyopuyo en python
python dans virtualenv
PPAP en Python
Filtrage de texte avec des baies naïves de sklearn