Lernen Sie Naive Bayes, das in Python 3.3 implementiert ist, auf einer Webseite kennen, die mit der Bing-API abgerufen wurde. Lassen Sie die Sätze klassifiziert werden

** Dieser Beitrag ist der zweite Tagesartikel von Real Escape Advent Calendar 2013. ** ** **

Zuletzt implementiert Naive Bayes. Da ich es mit großer Anstrengung gemacht habe, habe ich es mit dem Code geschrieben, den ich bisher geschrieben habe, um es zu einem praktischen System zu machen.

Ich habe den gesamten Code außer dem API-Schlüssel auf Github hochgeladen. Verwenden Sie ihn daher bitte so, wie er ist, wenn Sie möchten. https://github.com/katryo/bing_search_naive_bayes

Umriss von dem, was ich gemacht habe

  1. Verwenden Sie bei der angegebenen Suchabfrage die Bing-API, um das Web zu durchsuchen und 50 Webseiten abzurufen.
  2. Machen Sie die Sätze in der erworbenen HTML-Datei Bag-of-Words und lernen Sie Naive Bayes mit der Suchabfrage als Kategorie. Der gelernte Klassifikator wird in Gurke umgewandelt und gespeichert.
  3. Verwenden Sie den Klassifikator, um zu erraten, zu welcher Kategorie ein bestimmter Satz gehört

Durch die Kombination der oben genannten drei Funktionen haben wir ein System geschaffen, das Lerndaten erfassen, lernen und klassifizieren kann.

1. Durchsuchen Sie das Web mit der Bing-API

Basierend auf http://o-tomox.hatenablog.com/entry/2013/09/25/191506 von @ o-tomox habe ich einen verbesserten Wrapper geschrieben, der mit Python 3.3 funktioniert.

Schreiben Sie den Bing-API-Schlüssel im Voraus in eine Datei mit dem Namen my_api_keys.py.

my_api_keys.py


BING_API_KEY = 'abcdefafdafsafdafasfaafdaf'

Bitte ignorieren Sie es mit .gitignore. Andernfalls wird der API-Schlüssel veröffentlicht.

Das Folgende ist ein Wrapper für die Bing-API.

bing.py


# -*- coding: utf-8 -*-
import urllib
import requests
import sys
import my_api_keys


class Bing(object):
    #Auf der gleichen Ebene meine_api_keys.Erstellen Sie dort eine Datei mit dem Namen py und BING_API_Schreiben Sie den SCHLÜSSEL.
    # my_api_keys.Halten Sie py gitignore.
    def __init__(self, api_key=my_api_keys.BING_API_KEY):
        self.api_key = api_key

    def web_search(self, query, num_of_results, keys=["Url"], skip=0):
        """
in Schlüsseln'ID','Title','Description','DisplayUrl','Url'Kann betreten
        """
        #Grundlegende URL
        url = 'https://api.datamarket.azure.com/Bing/Search/Web?'
        #Maximale Anzahl, die gleichzeitig zurückgegeben wird
        max_num = 50
        params = {
            "Query": "'{0}'".format(query),
            "Market": "'ja-JP'"
        }
        #Von json empfangenes Format
        request_url = url + urllib.parse.urlencode(params) + "&$format=json"
        results = []

        #Häufigkeit, mit der die API mit maximaler Anzahl wiederholt wird
        repeat = int((num_of_results - skip) / max_num)
        remainder = (num_of_results - skip) % max_num

        #Wiederholen Sie den Vorgang, indem Sie die API mit der maximalen Anzahl treffen
        for i in range(repeat):
            result = self._hit_api(request_url, max_num, max_num * i, keys)
            results.extend(result)
        #verbleibend
        if remainder:
            result = self._hit_api(request_url, remainder, max_num * repeat, keys)
            results.extend(result)

        return results

    def related_queries(self, query, keys=["Title"]):
        """
in Schlüsseln'ID','Title','BaseUrl'Kann betreten
        """
        #Grundlegende URL
        url = 'https://api.datamarket.azure.com/Bing/Search/RelatedSearch?'
        params = {
            "Query": "'{0}'".format(query),
            "Market": "'ja-JP'"
        }
        #Von json empfangenes Format
        request_url = url + urllib.parse.urlencode(params) + "&$format=json"
        results = self._hit_api(request_url, 50, 0, keys)
        return results

    def _hit_api(self, request_url, top, skip, keys):
        #Endgültige URL für das Aufrufen der API
        final_url = "{0}&$top={1}&$skip={2}".format(request_url, top, skip)
        response = requests.get(final_url, 
                                auth=(self.api_key, self.api_key), 
                                headers={'User-Agent': 'My API Robot'}).json()
        results = []
        #Holen Sie sich die angegebenen Informationen aus den zurückgegebenen Artikeln
        for item in response["d"]["results"]:
            result = {}
            for key in keys:
                result[key] = item[key]
            results.append(result)
        return results


if __name__ == '__main__':
    # bing_api.Wenn py alleine verwendet wird, wird es zu einem Werkzeug, um 50 Elemente mit dem eingegebenen Wort zu suchen und das Ergebnis anzuzeigen.
    for query in sys.stdin:
        bing = Bing()
        results = bing.web_search(query=query, num_of_results=50, keys=["Title", "Url"])
        print(results)

Mit diesem Bing-API-Wrapper habe ich ein Skript geschrieben, das 50 Suchergebnisseiten lokal speichert.

fetch_web_pages.py


from bing_api import Bing
import os
import constants
from web_page import WebPage

if __name__ == '__main__':
    bing = Bing()
    if not os.path.exists(constants.FETCHED_PAGES_DIR_NAME):
        os.mkdir(constants.FETCHED_PAGES_DIR_NAME)
    os.chdir(constants.FETCHED_PAGES_DIR_NAME)
    results = bing.web_search(query=constants.QUERY, num_of_results=constants.NUM_OF_FETCHED_PAGES, keys=['Url'])
    for i, result in enumerate(results):
        page = WebPage(result['Url'])
        page.fetch_html()
        f = open('%s_%s.html' % (constants.QUERY, str(i)), 'w')
        f.write(page.html_body)
        f.close()

Erstellen Sie außerdem eine Datei mit dem Namen constants.py und schreiben Sie den Namen des Verzeichnisses, in dem der HTML-Code der Abfrage- und Suchergebnisse gespeichert ist. Dieses Mal werde ich zuerst nach der Abfrage "defekt" suchen.

constants.py


FETCHED_PAGES_DIR_NAME = 'fetched_pages'
QUERY = 'Fraktur'
NUM_OF_FETCHED_PAGES = 50
NB_PKL_FILENAME = 'naive_bayes_classifier.pkl'

Ich habe eine Klasse namens WebPage erstellt, um die Handhabung der erfassten Webseite zu vereinfachen. Rufen Sie basierend auf der von der Bing-API erhaltenen URL HTML ab, überprüfen Sie den Zeichencode mit cChardet und löschen Sie das störende HTML-Tag mit einem regulären Ausdruck.

web_page.py


import requests
import cchardet
import re


class WebPage():
    def __init__(self, url=''):
        self.url = url

    def fetch_html(self):
        try:
            response = requests.get(self.url)
            self.set_html_body_with_cchardet(response)
        except requests.exceptions.ConnectionError:
            self.html_body = ''

    def set_html_body_with_cchardet(self, response):
        encoding_detected_by_cchardet = cchardet.detect(response.content)['encoding']
        response.encoding = encoding_detected_by_cchardet
        self.html_body = response.text

    def remove_html_tags(self):
        html_tag_pattern = re.compile('<.*?>')
        self.html_body = html_tag_pattern.sub('', self.html_body)

Legen Sie nun den obigen Code in dasselbe Verzeichnis.

$ python fetch_web_pages.py

Ausführen. Es dauert einen Moment, bis die Bing-API aufgerufen wird, um 50 URLs abzurufen. Es dauert jedoch etwas, bis eine HTTP-Anforderung an jede der 50 URLs gesendet und der HTML-Code abgerufen wird. Ich denke, es wird ungefähr 30 Sekunden dauern.

Wenn Sie fertig sind, schauen Sie sich das Verzeichnis fetched_pages an. Sie sollten eine HTML-Datei von Fraktur_0.html bis Fraktur.49.html haben.

2. Lernen Sie aus 50 HTML-Dateien

Jetzt kommt endlich die letzte Implementierung von Naive Bayes ins Spiel.

naive_bayes


#coding:utf-8
# http://gihyo.jp/dev/serial/01/machine-learning/Python3 mit der Basilian-Filter-Implementierung von 0003.Verbessert, um für 3 lesbar zu sein
import math
import sys
import MeCab


class NaiveBayes:
    def __init__(self):
        self.vocabularies = set()
        self.word_count = {}  # {'Maßnahmen gegen Pollinose': {'Sugi Pollen': 4, 'Medizin': 2,...} }
        self.category_count = {}  # {'Maßnahmen gegen Pollinose': 16, ...}

    def to_words(self, sentence):
        """
Eingang: 'Alles für mich'
Ausgabe: tuple(['alles', 'mich selber', 'von', 'Wie', 'Was'])
        """
        tagger = MeCab.Tagger('mecabrc')  #Sie können einen anderen Tagger verwenden
        mecab_result = tagger.parse(sentence)
        info_of_words = mecab_result.split('\n')
        words = []
        for info in info_of_words:
            #Wenn Sie durch Macab teilen, steht "" am Ende des Satzes davor'EOS'Kommt
            if info == 'EOS' or info == '':
                break
                # info => 'Nana\t Assistent,Letzte Hilfe,*,*,*,*,Nana,N / a,N / a'
            info_elems = info.split(',')
            #Sechstens gibt es Wörter, die nicht verwendet werden. Wenn der sechste ist'*'Wenn ja, geben Sie die 0 ein
            if info_elems[6] == '*':
                # info_elems[0] => 'Van Rossam\t Substantiv'
                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):
        #Berechnung des Bayes'schen Gesetzes
        numerator = self.num_of_appearance(word, category) + 1  # +1 ist die Laplace-Methode zur additiven Glättung
        denominator = sum(self.word_count[category].values()) + len(self.vocabularies)

        #In Python3 wird die Division automatisch verschoben
        prob = numerator / denominator
        return prob

    def score(self, words, category):
        score = math.log(self.prior_prob(category))
        for word in words:
            score += math.log(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 ist eine Open-Source-Programmiersprache, die vom Niederländer Guido Van Rossam entwickelt wurde.
Es ist eine Art objektorientierte Skriptsprache und wird in Europa und den USA zusammen mit Perl häufig verwendet. Benannt nach der Comedy-Show "Flying Monty Python" des britischen Fernsehsenders BBC.
Python bedeutet auf Englisch Reptilien-Nishiki-Schlange und wird manchmal als Maskottchen oder Symbol in der Python-Sprache verwendet. Python ist eine allgemeine Hochsprache. Es wurde mit dem Fokus auf Programmiererproduktivität und Codezuverlässigkeit entwickelt und verfügt über eine große, praktische Standardbibliothek mit minimaler Kernsyntax und Semantik.
Es unterstützt Zeichenfolgenoperationen mit Unicode, und die japanische Verarbeitung ist standardmäßig möglich. Es unterstützt viele Plattformen (Arbeitsplattformen) und verfügt über zahlreiche Dokumente und Bibliotheken, sodass seine Verwendung in der Branche zunimmt.
             ''',
             'Python')
    nb.train('''Ruby ist eine objektorientierte Skriptsprache, die von Yukihiro Matsumoto (allgemein bekannt als Matz) entwickelt wurde.
Realisiert objektorientierte Programmierung in Bereichen, in denen traditionell Skriptsprachen wie Perl verwendet wurden.
Ruby wurde ursprünglich am 24. Februar 1993 geboren und im Dezember 1995 auf fj angekündigt.
Der Name Ruby ist, weil die Programmiersprache Perl dasselbe ausspricht wie Pearl, der Geburtsstein des Juni.
Es wurde nach dem Rubin des Geburtssteins von Matsumotos Kollegen (Juli) benannt.
             ''',
             'Ruby')
    doc = 'Open Source von Guido Van Rossam'
    print('%s =>Geschätzte Kategorie: %s' % (doc, nb.classify(doc)))  #Geschätzte Kategorie:Sollte Python sein

    doc = 'Eine reine objektorientierte Sprache.'
    print('%s =>Geschätzte Kategorie: %s' % (doc, nb.classify(doc)))  #Geschätzte Kategorie:Sollte Ruby sein

Trainieren Sie mithilfe dieser Naive Bayes-Implementierung und der heruntergeladenen HTML-Datei den Klassifizierer, bei dem es sich um ein Naive Bayes-Objekt handelt.

Es ist eine Verschwendung, das trainierte Naive Bayes-Objekt jedes Mal wegzuwerfen. Speichern Sie es also mithilfe der Gurkenbibliothek.

Klicken Sie hier, um ein Skript zum Lernen und Speichern zu erhalten.

train_with_fetched_pages.py


import os
import pickle
import constants
from web_page import WebPage
from naive_bayes import NaiveBayes


def load_html_files():
    """
Verwenden Sie diese Option unter der Annahme, dass sich die HTML-Datei im Verzeichnis befindet
    """
    pages = []
    for i in range(constants.NUM_OF_FETCHED_PAGES):
        with open('%s_%s.html' % (constants.QUERY, str(i)), 'r') as f:
            page = WebPage()
            page.html_body = f.read()
        page.remove_html_tags()
        pages.append(page)
    return pages

if __name__ == '__main__':
    #Wenn Sie es wieder an einem anderen Ort verwenden möchten, machen Sie es zu einer Funktion
    if not os.path.exists(constants.FETCHED_PAGES_DIR_NAME):
        os.mkdir(constants.FETCHED_PAGES_DIR_NAME)
    os.chdir(constants.FETCHED_PAGES_DIR_NAME)
    pages = load_html_files()
    pkl_nb_path = os.path.join('..', constants.NB_PKL_FILENAME)

    #Wenn Sie bereits ein Naive Bayes-Objekt eingelegt haben, trainieren Sie es
    if os.path.exists(pkl_nb_path):
        with open(pkl_nb_path, 'rb') as f:
            nb = pickle.load(f)
    else:
        nb = NaiveBayes()
    for page in pages:
        nb.train(page.html_body, constants.QUERY)
    #Ich habe es so viel gelernt, also lass es uns retten
    with open(pkl_nb_path, 'wb') as f:
        pickle.dump(nb, f)

Legen Sie den obigen Quellcode in dasselbe Verzeichnis und machen Sie dasselbe wie zuvor

$ python train_with_fetched_web_pages.py

Führen Sie das Lernen durch und speichern Sie den Klassifikator unter. Dieses Mal dauert es nicht lange, da es nicht über HTTP mit der Außenwelt kommuniziert. In meinem Fall dauerte es weniger als 5 Sekunden.

3. Kategorie nach gespeichertem Klassifikator

Mit dem obigen Verfahren konnten wir eine Abfrage = eine Kategorie namens "Fraktur" lernen. Es kann jedoch nicht nur einer Kategorie zugeordnet werden. Daher werde ich den obigen Vorgang mehrmals mit verschiedenen Abfragen wiederholen.

Wiederholung

Schreiben Sie zuerst QUERY in constants.py neu.

constants.py


QUERY ="Magen lehnen"#Umgeschrieben von 'gebrochen'

Rufen Sie dann den HTML-Code mit der Bing-API ab.

$ python fetch_web_pages.py

Trainieren Sie den unter dem Namen naive_bayes_classifier.pkl gespeicherten Naive Bayes-Klassifikator mit 50 abgerufenen HTML-Dateien.

$ python train_with_fetched_web_pages.py

Wiederholen Sie die obige Arbeit mehrmals, indem Sie die Konstanten neu schreiben. Fragen Sie nach "Gegenmaßnahmen gegen Pollinose" und "Wurmzähne".

Kategorie

Nun, das Lernen ist vorbei. Endlich beginnt die Produktion von hier. Nehmen Sie eine Zeichenfolge aus der Standardeingabe und lassen Sie den Klassifizierer kategorisieren, welcher Kategorie die Zeichenfolge zugewiesen werden soll.

Das zu klassifizierende Skript ist wie folgt einfach. Laden Sie zuerst das eingelegte Naive Bayes-Objekt und entfernen Sie es aus dem Salz. Führen Sie dann jedes Mal, wenn sys.stdin eingegeben wird, einfach die classify () -Methode des NaiveBayes-Objekts aus und zeigen Sie das Ergebnis an.

classify.py


# -*- coding: utf-8 -*-
import pickle
import constants
import sys

if __name__ == '__main__':
    with open(constants.NB_PKL_FILENAME, 'rb') as f:
        nb = pickle.load(f)
    for query in sys.stdin:
        result = nb.classify(query)
        print('Die abgeleitete Kategorie ist%s' % result)

Machen wir das.

$ python classify_inputs.py

Es funktioniert als Terminal-Tool. Geben Sie also die Zeichenfolge so ein, wie sie ist. Zunächst die [Allergien] von Wikipedia (http://en.wikipedia.org/wiki/%E3%82%A2%E3%83%AC%E3%83%AB%E3%82%AE%E3%83%BC) ) Seite "Allergie" bedeutet, dass eine Immunreaktion übermäßig gegen ein bestimmtes Antigen auftritt. Die Immunreaktion eliminiert fremde Fremdsubstanzen (Antigene). Es ist eine unverzichtbare physiologische Funktion für den lebenden Körper. "

allergie.png

Erfolg! Es wurde in die Kategorie "Gegenmaßnahmen gegen Pollinose" eingestuft.

Als nächstes der Text auf der Seite von Lion's Clinica "Nach einer Mahlzeit oder einem Snack metabolisieren die Bakterien in der Plaque Zucker. Die Oberfläche der mit Plaque bedeckten Zähne wird sauer, weil sie Säure produziert. "

tooth_brush.png

Dies ist auch erfolgreich. Es wurde vermutet, dass es sich um die Kategorie "Wurmzahn" handelt.

Zusammenfassung

Dieses Mal habe ich Naive Bayes verwendet, das ich selbst implementiert habe, um überwachtes Lernen mithilfe von Web-Suchergebnissen durchzuführen. Ich habe es mehrmals versucht, aber es funktioniert ziemlich gut.

Diese Implementierung zählt die Anzahl der Vorkommen aller angezeigten Wörter, einschließlich übermäßig häufiger Wörter wie "ha" und "o". Ursprünglich sollten wir tf-idf verwenden, um den Wert von Wörtern zu verringern, die zu häufig vorkommen, ihre Eigenschaften zu verringern und die Berechnungskosten zu senken, diesmal jedoch nicht. Dies liegt daran, dass die für das Training verwendeten Daten klein waren und die Berechnung nicht lange dauerte. Als zukünftige Aufgabe möchte ich Methoden wie tf-idf und LSA (Latent Meaning Analysis) verwenden, um die Berechnungskosten zu reduzieren oder die Genauigkeit zu verbessern.

Wenn Sie eine Bibliothek wie scikit-learn verwenden, sollte es einfacher und bequemer sein, Hochleistungsglättung und tfidf zu verwenden, daher würde ich dies gerne beim nächsten Mal tun.

Pushed to Github, schauen Sie also bitte vorbei, wenn Sie möchten. Bitte gib mir noch einen Stern.

Vorschau beim nächsten Mal

Hinzufügen einer Funktion zur Berechnung der Ähnlichkeit aus der Häufigkeit des gleichzeitigen Auftretens von Wörtern, die einmal von Naive Bayes entfernt waren. Nächstes Mal werden Sie die Tränen der Zeit sehen. http://qiita.com/katryo/items/b6962facf744e93735bb

Recommended Posts

Lernen Sie Naive Bayes, das in Python 3.3 implementiert ist, auf einer Webseite kennen, die mit der Bing-API abgerufen wurde. Lassen Sie die Sätze klassifiziert werden
Führen Sie den Ausgabecode auf dem lokalen Webserver in Python als "A, gibt vor, B zu sein" aus
Klicken Sie auf die Web-API in Python
Python VBA, um mit Selenium die gesamte WEB-Seite zu erfassen
Treffen Sie eine Methode einer Klasseninstanz mit der Python Bottle Web API
Laden Sie mit Python Dateien im Web herunter
Berechnen Sie mithilfe des in Python 3.3 implementierten Naive Bayes-Klassifikators die Ähnlichkeit aus der Häufigkeit des gleichzeitigen Auftretens von Wörtern in Sätzen und Zeichenfolgen.
Lassen Sie Python die durchschnittliche Punktzahl einer Seite mithilfe der PageSpeed Insights-API messen
[Python] Holen Sie sich die Dateien mit Python in den Ordner
Erstellen Sie eine neue Seite im Zusammenfluss mit Python
Extrahieren Sie mit Python Daten von einer Webseite
Verwenden Sie tkinter, um den Ausgabecode in Python als "A und vorgeben, B zu sein" zu verschieben
Automatisieren Sie das Entfernen des Hintergrunds für die neuesten Porträts in einem Verzeichnis mit Python und API
[Python3] Machen Sie einen Screenshot einer Webseite auf dem Server und schneiden Sie sie weiter zu
[Für Anfänger] Web-Scraping mit Python "Greifen Sie auf die URL auf der Seite zu, um den Inhalt abzurufen."
Machen Sie mit Python einen Haltepunkt auf der c-Ebene
Schreiben Sie in Python ein logarithmisches Histogramm auf die x-Achse
Test.py wird auf dem Webserver in Python3 nicht angezeigt.
Ein Hinweis zum Aufrufen der Facebook-API mit dem Python SDK
Ein Hinweis beim Berühren der Gesichtserkennungs-API von Microsoft mit Python
[Teil 2] Crawlen mit Python! Klicken Sie auf die Webseite, um sich zu bewegen!
Speichern Sie Bilder im Web mit Python (Colab) auf einem Laufwerk.
Maschinelles Python-Lernen ohne Entwicklungsumgebung. Im Azure-Notizbuch (Jupyter-Notizbuch in Azure) heißt es: "Lernen wir, indem wir mit Ayaka Ikezawa programmieren!" Ich nahm an einem Mathematikkurs für maschinelles Lernen teil [Bayes 'Theorem]