Data Science-Projekt von der Forschung bis zur Implementierung am Beispiel von Talking Hat

Published on November 22, 2018

Data Science-Projekt von der Forschung bis zur Implementierung am Beispiel von Talking Hat


    Vor einem Monat startete Lenta einen Wettbewerb, bei dem derselbe Talking Hat von Harry Potter bestimmt, wer einer der vier Fakultäten Zugang zum sozialen Netzwerk der Teilnehmer gewährt hat. Die Konkurrenz ist nicht schlecht, die Namen, die unterschiedlich klingen, werden in verschiedenen Fakultäten definiert, und ähnliche englische und russische Vor- und Nachnamen werden auf ähnliche Weise verteilt. Ich weiß nicht, ob die Verteilung nur von Vor- und Nachnamen abhängt und ob die Anzahl der Freunde oder andere Faktoren berücksichtigt werden. Dieser Wettbewerb hat jedoch zur Idee dieses Artikels geführt: Versuchen Sie, einen Klassifikator von Grund auf zu trainieren, mit dem Benutzer auf verschiedene Fakultäten verteilt werden können.


    In dem Artikel werden wir ein einfaches ML-Modell erstellen, das die Menschen abhängig von ihrem Vor- und Nachnamen an die Harry-Potter-Fakultäten verteilt und dabei einen kleinen Forschungsprozess nach der CRISP- Methodik durchläuft . Nämlich wir:


    • Wir formulieren das Problem;
    • Wir untersuchen mögliche Lösungsansätze und formulieren Datenanforderungen (Lösungsmethoden und Daten);
    • Sammeln Sie die notwendigen Daten (Lösungsmethoden und Daten);
    • Durchsuchen des zusammengestellten Datensatzes (Exploratory Research);
    • Features aus Rohdaten extrahieren (Feature Engineering);
    • Wir werden ein Modell des maschinellen Lernens trainieren (Modellbewertung);
    • Vergleichen wir die erhaltenen Ergebnisse, bewerten wir die Qualität der erhaltenen Lösungen und wiederholen wir gegebenenfalls die Absätze 2-6.
    • Wir packen die Lösung in einen Service, der genutzt werden kann (Produktion).


    Diese Aufgabe mag trivial erscheinen, daher werden wir den gesamten Vorgang (so dass er weniger als 2 Stunden dauert) und diesen Artikel (so dass seine Lesezeit weniger als 15 Minuten beträgt) zusätzlich einschränken.


    Wenn Sie bereits in die wunderbare und wunderbare Welt von Data Science vertieft sind und Kagglit ständig von niemandem gesehen wird oder Sie (Gott bewahre es) Ihre Hadup-Länge bei Besprechungen mit Kollegen messen möchten, wird Ihnen der Artikel höchstwahrscheinlich einfach und uninteressant erscheinen. Darüber hinaus ist die Qualität der fertigen Modelle nicht der Hauptwert dieses Artikels. Wir haben dich gewarnt. Lass uns gehen.


    Für neugierige Leser steht auch ein Githab-Repository mit dem im Artikel verwendeten Code zur Verfügung . Im Fehlerfall öffnen Sie bitte die PR.


    Formulieren Sie die Aufgabe


    Das Lösen eines Problems, das keine klaren Entscheidungskriterien hat, kann unendlich lang sein. Daher entscheiden wir uns sofort für eine Lösung, mit der wir die Antwort „Gryffindor“, „Kogtevran“, „Puffendoi“ oder „Slytherin“ als Antwort auf die eingegebene Zeichenfolge erhalten.


    Grundsätzlich wollen wir eine Blackbox:


    "Гарри поттер" => [?] => Griffindor

    Der originale schwarze Hut verteilte die jungen Zauberer je nach Charakter und persönlichen Qualitäten an die Fakultäten. Da uns die Daten zu Charakter und Persönlichkeit der Aufgabe nicht zur Verfügung stehen, werden wir den Vor- und Nachnamen des Teilnehmers verwenden, wobei zu berücksichtigen ist, dass wir in diesem Fall die Charaktere des Buches an die Fakultäten verteilen müssen, die ihren Heimatfakultäten aus dem Buch entsprechen. Ja, und die Potter-Liebhaber werden definitiv verärgert sein, wenn unsere Entscheidung Harry an Puffendoi oder Kogtevran verteilt (aber es muss Harry und Slytherin mit der gleichen Wahrscheinlichkeit zu Harry schicken, um den Geist des Buches zu vermitteln).


    Wenn wir über Wahrscheinlichkeiten sprechen, dann formalisieren wir das Problem in strengeren mathematischen Begriffen. Aus Sicht von Data Science lösen wir das Problem der Klassifizierung, nämlich das Zuweisen eines Objekts (einer Zeichenfolge in Form eines Vor- und Nachnamens) zu einer bestimmten Klasse (tatsächlich handelt es sich nur um eine Beschriftung oder eine Beschriftung, die eine Ziffer oder vier Variablen mit einem Ja / Nein-Wert sein kann) ). Wir verstehen, dass es zumindest im Fall von Harry richtig sein wird, zwei Antworten zu geben: Gryffindor und Slytherin. Daher ist es besser, nicht eine bestimmte Abteilung vorherzusagen, die der Hut bestimmt, sondern die Wahrscheinlichkeit, dass eine Person an diese Abteilung verteilt wird, und daher unsere Entscheidung zu treffen eine Art Funktion


    f(<Undmmir> <Famundlundmir>)=(Pgrichffichndor;Pravenclaw;Phufflpuff;Pslichtherichn)


    Metriken und Qualitätsbewertung


    Die Aufgabe und das Ziel sind formuliert, Jetzt werden wir uns überlegen, wie wir es lösen könnenaber das ist noch nicht alles. Um mit der Studie fortzufahren, müssen Sie die Qualitätsmetriken eingeben. Mit anderen Worten - um zu bestimmen, wie wir zwei verschiedene Lösungen miteinander vergleichen.


    Alles im Leben ist gut und einfach - wir verstehen intuitiv, dass ein Spam-Erkenner ein Minimum an Spam in den Posteingang und ein Maximum an erforderlichen Briefen überspringen muss und die erforderlichen Briefe auf keinen Fall an Spam senden sollte.


    Die Realität ist komplexer und Bestätigung , dass eine große Anzahl von Artikeln , die erklären , wie und welche Metriken verwendet werden. Es ist am besten zu verstehen, dass dies dem Üben hilft, aber es ist ein so umfangreiches Thema, dass wir versprechen, einen separaten Beitrag darüber zu verfassen und einen offenen Tisch zu erstellen, damit jeder herumspielen und in der Praxis verstehen kann, wie es sich unterscheidet.


    Der Haushalt, bei dem wir das Beste auswählen, wird die ROC AUC sein . Dies ist genau das, was wir in diesem Fall von der Metrik erwarten: Je weniger falsch-positive Ergebnisse und je genauer die tatsächliche Vorhersage ist, desto höher ist die ROC-AUC.


    Im idealen Modell ist die ROC AUC 1, im idealen Zufallsmodell, das Klassen absolut zufällig definiert - 0,5.


    RO.C AUC[0,5;1]


    Algorithmen


    Unsere Blackbox sollte die Verteilung der Helden der Bücher berücksichtigen, einen anderen Vor- und Nachnamen als Eingabe verwenden und das Ergebnis ausgeben. Um das Klassifizierungsproblem zu lösen, können Sie verschiedene Algorithmen für maschinelles Lernen verwenden:


    neuronale Netze, Faktorisierungsmaschinen, lineare Regression oder zum Beispiel SVM.


    Entgegen der landläufigen Meinung beschränkt sich Data Science nicht nur auf neuronale Netze. Um diese Idee zu popularisieren, werden in diesem Artikel neuronale Netze als Übung für einen neugierigen Leser hinterlassen . Diejenigen, die keinen einzigen Kurs über Datenanalyse (besonders subjektiv die besten - von SLM) besucht haben oder einfach n Nachrichten über maschinelles Lernen oder KI lesen , die jetzt sogar in den Amateur Fisherman-Magazinen veröffentlicht werden, haben wahrscheinlich die Namen allgemeiner Algorithmengruppen kennengelernt : Absacken, Boosten, Support Vector Machine (SVM), lineare Regression. Damit werden wir unser Problem lösen.


    Und um genauer zu sein, vergleichen wir miteinander:


    • Lineare Regression
    • Boosting (XGboost, LightGBM)
    • Entscheidende Bäume (genau genommen ist dies die gleiche Steigerung, aber wir werden sie separat entfernen: Zusätzliche Bäume)
    • Absacken (Zufälliger Wald)
    • SVM

    Die Aufgabe, jeden Hogwarts-Studenten auf eine der Fakultäten zu verteilen, die wir lösen können, indem wir die entsprechende Fakultät definieren. Genau genommen reduziert sich diese Aufgabe jedoch auf die Lösung des Problems, die Zugehörigkeit zu jeder Klasse separat zu bestimmen. In diesem Artikel haben wir uns daher zum Ziel gesetzt, 4 Modelle zu erhalten, eines für jede Abteilung.


    Daten


    Es ist eine der schwierigsten und zeitaufwändigsten Aufgaben in Data Science, den richtigen Datensatz für das Lernen zu finden und vor allem - legal für die Verwendung in den richtigen Zielen -. Für unsere Aufgabe nehmen wir die Daten aus Wikia in die Welt von Harry Potter. Unter diesem Link finden Sie beispielsweise alle Charaktere, die an der Fakultät von Gryffindor studiert haben. Es ist wichtig, dass die Daten in diesem Fall für nichtkommerzielle Zwecke verwendet werden, damit wir die Lizenz dieser Website nicht verletzen .



    Für diejenigen, die denken, dass Data Scientists so coole Typen sind, gehe ich zu Data Scientists und lasse sie mich unterrichten. Wir erinnern Sie daran, dass es einen Schritt wie das Bereinigen und Vorbereiten von Daten gibt. Die heruntergeladenen Daten müssen manuell moderiert werden, um beispielsweise den "Siebten Präfekten von Gryffindor" zu entfernen und das "Unbekannte Mädchen von Gryffindor" halbautomatisch zu entfernen. In der realen Arbeit wird ein proportional großer Teil der Aufgabe immer mit der Aufbereitung, Bereinigung und Wiederherstellung fehlender Werte in einem Datensatz verbunden.


    Ein bisschen Strg + C & Strg + V und am Ausgang erhalten wir 4 Textdateien, in denen sich die Namen der Zeichen in 2 Sprachen befinden: Englisch und Russisch.


    Wir untersuchen die gesammelten Daten (EDA, Exploratory Data Analysis)


    Zu diesem Zeitpunkt haben wir 4 Dateien mit den Namen der Studenten der Fakultäten, schauen wir uns das genauer an:


    $ ls ../input
    griffindor.txt hufflpuff.txt  ravenclaw.txt  slitherin.txt

    Jede Datei enthält 1 Vor- und Nachnamen (falls vorhanden) des Schülers pro Zeile:


    $ wc -l ../input/*.txt
         250 ../input/griffindor.txt
         167 ../input/hufflpuff.txt
         180 ../input/ravenclaw.txt
         254 ../input/slitherin.txt
         851 total

    Die gesammelten Daten sind:


    $ cat ../input/griffindor.txt | head -3 && cat ../input/griffindor.txt | tail -3
    Юан Аберкромби
    Кэти Белл
    Бем
    Charlie Stainforth
    Melanie Stanmore
    Stewart

    Unsere ganze Idee basiert auf der Annahme, dass es etwas in den Vor- und Nachnamen gibt, das unsere Black Box (oder unser schwarzer Hut) unterscheiden kann.


    Der Algorithmus kann die Zeilen so wie sie sind füttern, aber das Ergebnis wird nicht gut sein, da die Basismodelle nicht verstehen können, was „Draco“ von „Harry“ unterscheidet. Daher müssen wir die Zeichen aus unseren Vor- und Nachnamen extrahieren.


    Datenaufbereitung (Feature Engineering)


    Zeichen (oder Merkmale, aus dem Englischen. Merkmal - Eigenschaft) sind die unterscheidenden Eigenschaften des Objekts. Die Häufigkeit, mit der eine Person im letzten Jahr die Arbeit gewechselt hat, die Anzahl der Finger an der linken Hand, die Größe des Motors eines Autos, unabhängig davon, ob der Kilometerstand des Autos 100.000 km beträgt oder nicht. Alle Arten von Klassifikationen von Zeichen wurden von einer sehr großen Anzahl erfunden, es gibt in dieser Hinsicht kein einzelnes System und es kann kein solches geben, daher werden wir Beispiele geben, wie die Zeichen aussehen können:


    1. Rationale Nummer
    2. Kategorie (bis zu 12, 12-18 oder 18+)
    3. Binärwert (Rückgabe des ersten Darlehens oder nicht)
    4. Datum, Farbe, Freigabe usw.

    Die Suche (oder Bildung) von Merkmalen (in englischer Sprache von Feature Engineering ) wird sehr häufig einer separaten Forschungsstufe oder der Arbeit eines Datenanalysespezialisten zugeordnet. Dabei helfen der gesunde Menschenverstand, die Erfahrung und das Testen von Hypothesen. Das Erraten der richtigen Zeichen auf einmal ist eine Frage der Kombination von vollständiger Hand, grundlegendem Wissen und Glück. Manchmal gibt es Schamanismus, aber der allgemeine Ansatz ist sehr einfach: Sie müssen das tun, was Ihnen in den Sinn kommt, und dann prüfen, ob die Lösung durch Hinzufügen eines neuen Attributs verbessert wurde. Als Zeichen für unsere Aufgabe können wir beispielsweise die Anzahl der Zischlaute im Namen verwenden.


    In der ersten Version (da die vorliegende Data Science-Studie wie ein Meisterwerk ist und niemals abgeschlossen werden kann) verwendet unser Modell die folgenden Attribute für den Vor- und Nachnamen:


    1. 1 und der letzte Buchstabe des Wortes - Vokal oder Konsonant
    2. Die Anzahl der Doppelvokale und Konsonanten
    3. Anzahl der Vokale, Konsonanten, taub, stimmhaft
    4. Vorname, Nachname Länge
    5. ...

    Dazu nehmen wir dieses Repository als Grundlage und fügen eine Klasse hinzu, damit sie für lateinische Buchstaben verwendet werden kann. Dies gibt uns die Möglichkeit zu bestimmen, wie jeder Buchstabe klingt.


    >> from Phonetic import RussianLetter, EnglishLetter
    >> RussianLetter('р').classify()
    {'consonant': True,
     'deaf': False,
     'hard': False,
     'mark': False,
     'paired': False,
     'shock': False,
     'soft': False,
     'sonorus': True,
     'vowel': False}
    >> EnglishLetter('d').classify()
    {'consonant': True,
     'deaf': False,
     'hard': True,
     'mark': False,
     'paired': False,
     'shock': False,
     'soft': False,
     'sonorus': True,
     'vowel': False}

    Nun können wir einfache Funktionen zur Berechnung von Statistiken definieren, zum Beispiel:


    def starts_with_letter(word, letter_type='vowel'):
        """
        Проверяет тип буквы, с которой начинается слово.
        :param word: слово
        :param letter_type: 'vowel' или 'consonant'. Гласная или согласная.
        :return: Boolean
        """
        if len(word) == 0:
            return False
        return Letter(word[0]).classify()[letter_type]
    def count_letter_type(word):
        """
        Подсчитывает число букв разного типа в слове.
        :param word: слово
        :param debug: флаг для дебага
        :return: :obj:`dict` of :obj:`str` => :int:count
        """
        count = {
             'consonant': 0,
             'deaf': 0,
             'hard': 0,
             'mark': 0,
             'paired': 0,
             'shock': 0,
             'soft': 0,
             'sonorus': 0,
             'vowel': 0
        }
        for letter in word:
            classes = Letter(letter).classify()
            for key in count.keys():
                if classes[key]:
                    count[key] += 1
        return count

    Mit diesen Funktionen können wir die ersten Anzeichen bekommen:


    from feature_engineering import *
    >> print("Длина имени («Гарри»): ", len("Гарри"))
    Длина имени («Гарри»):  5
    >> print("Имя («Гарри») начинается с гласной: ", 
          starts_with_letter('Аптека', 'vowel'))
    Имя («Гарри») начинается с гласной:  True
    >> print("Фамилия («Поттер») начинается с согласной: ", 
          starts_with_letter('Гарри', 'consonant'))
    Фамилия («Поттер») начинается с согласной:  True
    >> count_Harry = count_letter_type("Гарри")
    >> print ("Количество удвоенных согласных в имени («Гарри»): ", count_Harry['paired'])
    Количество удвоенных согласных в имени («Гарри»):  1

    Genau genommen können wir mit diesen Funktionen eine Vektordarstellung des Strings erhalten, dh wir erhalten das Mapping:


    f(<Undmmir> <Famundlundmir>)=>(dlundnaundmenund,dlundnafamundlundund,...,zuüberlundhemittin derüber_glamitnsxfamundlundund)


    Jetzt können wir unsere Daten in Form eines Datensatzes präsentieren, der in den Algorithmus für maschinelles Lernen eingegeben werden kann:


    >> from data_loaders import load_processed_data
    >> hogwarts_df = load_processed_data()
    >> hogwarts_df.head()


    Als Ergebnis erhalten wir die folgenden Zeichen für jeden Schüler:


    >> hogwarts_df[hogwarts_df.columns].dtypes

    Die daraus resultierenden Zeichen
    name                              object
    surname                           object
    is_english                          bool
    name_starts_with_vowel              bool
    name_starts_with_consonant          bool
    name_ends_with_vowel                bool
    name_ends_with_consonant            bool
    name_length                        int64
    name_vowels_count                  int64
    name_double_vowels_count           int64
    name_consonant_count               int64
    name_double_consonant_count        int64
    name_paired_count                  int64
    name_deaf_count                    int64
    name_sonorus_count                 int64
    surname_starts_with_vowel           bool
    surname_starts_with_consonant       bool
    surname_ends_with_vowel             bool
    surname_ends_with_consonant         bool
    surname_length                     int64
    surname_vowels_count               int64
    surname_double_vowels_count        int64
    surname_consonant_count            int64
    surname_double_consonant_count     int64
    surname_paired_count               int64
    surname_deaf_count                 int64
    surname_sonorus_count              int64
    is_griffindor                      int64
    is_hufflpuff                       int64
    is_ravenclaw                       int64
    is_slitherin                       int64
    dtype: object

    Die letzten 4 Spalten enthalten Informationen darüber, für welche Fakultät der Student eingeschrieben ist.


    Lernalgorithmen


    Kurz gesagt, Algorithmen werden wie Menschen trainiert: Sie machen Fehler und lernen daraus. Um zu verstehen , wie viel sie irrten, verwendet Algorithmen die Fehlerfunktion (Funktionsverlust, Englisch . Loss-Funktion ).


    Der Lernprozess ist in der Regel sehr einfach und besteht aus mehreren Schritten:


    1. Machen Sie eine Vorhersage.
    2. Bewerten Sie den Fehler.
    3. Ändern Sie die Modellparameter.
    4. Wiederholen Sie 1-3, bis das Ziel erreicht ist, der Prozess nicht beendet wird oder die Daten ausgehen.
    5. Bewerten Sie die Qualität des Modells.


      In der Praxis ist natürlich alles etwas komplizierter. Zum Beispiel gibt es das Phänomen der Umschulung ( englische Überanpassung) - der Algorithmus kann sich buchstäblich merken, welche Zeichen der Antwort entsprechen, und so das Ergebnis für Objekte verschlechtern, die denen, für die er trainiert wurde, nicht ähnlich sind. Um dies zu vermeiden, gibt es verschiedene Techniken und Hacks.



    Wie oben erwähnt, lösen wir 4 Aufgaben: eine für jede Abteilung. Deshalb bereiten wir Daten für Slytherin vor:


    # Копируем данные, чтобы случайно не потерять что-нибудь нужное:
    >> data_full = hogwarts_df.drop(
        [
        'name', 
        'surname',
        'is_griffindor',
        'is_hufflpuff',
        'is_ravenclaw'
        ], 
        axis=1).copy()
    # Берем данные для обучения, сбросив целевую колонку:
    >> X_data = data_full.drop('is_slitherin', axis=1)
    # В качестве целевой будет колонка, которая содержит 1 для учеников Слизерина
    >> y = data_full.is_slitherin

    Während des Lernens vergleicht der Algorithmus seine Ergebnisse ständig mit realen Daten, da dieser Teil des Datensatzes zur Validierung zugewiesen wird. Die Regel des guten Tons wird auch berücksichtigt, um das Ergebnis des Algorithmus an einzelnen Daten zu bewerten, die der Algorithmus nie gesehen hat. Deshalb teilen wir nun die Stichprobe im Verhältnis 70/30 und trainieren den ersten Algorithmus:


    from sklearn.cross_validation import train_test_split
    from sklearn.ensemble import RandomForestClassifier
    # Фиксируем сид для воспроизводимоси результата
    >> seed = 7
    # Пропорции разделения датасета
    >> test_size = 0.3
    >> X_train, X_test, y_train, y_test = train_test_split(X_data, y, test_size=test_size, random_state=seed)
    >> rfc = RandomForestClassifier()
    >> rfc_model = rfc.fit(X_train, y_train)

    Ist fertig Wenn Sie nun Daten an die Eingabe dieses Modells senden, wird das Ergebnis erzeugt. Das macht Spaß, also werden wir zuerst prüfen, ob Harrys Modell einen Slytherin in Harry erkennt. Dazu bereiten wir zunächst die Funktionen vor, um die Vorhersage des Algorithmus zu erhalten:


    Code anzeigen
    from data_loaders import parse_line_to_hogwarts_df
    import pandas as pd
    def get_single_student_features (name):
        """
        Возвращает признаки для переданного имени
        :param name: string для имени и фамилии
        :return: pd.DataFrame объект с готовыми признаками
        """
        featurized_person_df = parse_line_to_hogwarts_df(name)
        person_df = pd.DataFrame(featurized_person_df,
            columns=[
             'name', 
             'surname', 
             'is_english',
             'name_starts_with_vowel', 
             'name_starts_with_consonant',
             'name_ends_with_vowel', 
             'name_ends_with_consonant',
             'name_length', 
             'name_vowels_count',
             'name_double_vowels_count',
             'name_consonant_count',
             'name_double_consonant_count',
             'name_paired_count',
             'name_deaf_count',
             'name_sonorus_count',
             'surname_starts_with_vowel', 
             'surname_starts_with_consonant',
             'surname_ends_with_vowel', 
             'surname_ends_with_consonant',
             'surname_length', 
             'surname_vowels_count',
             'surname_double_vowels_count',
             'surname_consonant_count',
             'surname_double_consonant_count',
             'surname_paired_count',
             'surname_deaf_count',
             'surname_sonorus_count',
            ],
                                 index=[0]
        )
        featurized_person = person_df.drop(
                            ['name', 'surname'], axis = 1
                            )
        return featurized_person
    def get_predictions_vector (model, person):
        """
        Предсказывает вероятности классов 
        :param model: обученная модель
        :param person: string полного имени
        :return: list вероятностей принадлежности классу
        """
        encoded_person = get_single_student_features(person)
        return model.predict_proba(encoded_person)[0]

    Und jetzt legen wir einen kleinen Testdatensatz fest, um die Ergebnisse des Algorithmus zu berücksichtigen.


    def score_testing_dataset (model):
        """
        Предсказывает результат на искусственном наборе данных.
        :param model: обученная модель
        """
        testing_dataset = [
                "Кирилл Малев", "Kirill Malev",
                "Гарри Поттер", "Harry Potter", 
                "Северус Снейп", "Северус Снегг","Severus Snape",
                "Том Реддл", "Tom Riddle", 
                "Салазар Слизерин", "Salazar Slytherin"]
        for name in testing_dataset: 
            print ("{} — {}".format(name, get_predictions_vector(model, name)[1]))
    score_testing_dataset(rfc_model)

    Кирилл Малев — 0.5
    Kirill Malev — 0.5
    Гарри Поттер — 0.0
    Harry Potter — 0.0
    Северус Снейп — 0.75
    Северус Снегг — 0.9
    Severus Snape — 0.5
    Том Реддл — 0.2
    Tom Riddle — 0.5
    Салазар Слизерин — 0.2
    Salazar Slytherin — 0.3

    Die Ergebnisse waren zweifelhaft. Auch der Gründer der Fakultät würde nach diesem Vorbild nicht in seine Fakultät gelangen. Daher müssen Sie die strenge Qualität bewerten: Sehen Sie sich die Metriken an, nach denen wir zu Beginn gefragt haben:


    from sklearn.metrics import accuracy_score, roc_auc_score, classification_report
    predictions = rfc_model.predict(X_test)
    print("Classification report: ")
    print(classification_report(y_test, predictions))
    print("Accuracy for Random Forest Model: %.2f" 
              % (accuracy_score(y_test, predictions) * 100))
    print("ROC AUC from first Random Forest Model: %.2f"
                 % (roc_auc_score(y_test, predictions)))

    Classification report: 
                 precision    recall  f1-score   support
              0       0.66      0.88      0.75       168
              1       0.38      0.15      0.21        89
    avg / total       0.56      0.62      0.56       257
    Accuracy for Random Forest Model: 62.26
    ROC AUC from first Random Forest Model: 0.51

    Es ist nicht verwunderlich, dass die Ergebnisse so zweifelhaft ausfielen - die ROC-AUC von etwa 0,51 legt nahe, dass das Modell etwas besser als ein Münzwurf vorhersagt.


    Ergebnisse testen. Qualitätsmetriken


    Anhand eines Beispiels haben wir oben untersucht, wie ein Algorithmus trainiert wird, der die sklearn-Schnittstellen unterstützt. Der Rest wird genauso trainiert, also müssen wir nur alle Algorithmen trainieren und die jeweils besten auswählen.



    Dies ist nicht schwierig, da für jeden von uns unterrichteten Algorithmus 1 Standardeinstellungen verwendet werden und außerdem ein ganzer Satz trainiert wird, wobei verschiedene Optionen durchlaufen werden, die die Qualität des Algorithmus beeinflussen. Diese Phase wird als Modelltuning oder Hyperparameteroptimierung bezeichnet, und ihr Wesen ist sehr einfach: Es wird der Satz von Einstellungen ausgewählt, der das beste Ergebnis liefert.


    from model_training import train_classifiers
    from data_loaders import load_processed_data
    import warnings
    warnings.filterwarnings('ignore')
    # Загружаем данные
    hogwarts_df = load_processed_data()
    # Оставляем только нужные колонки
    data_full = hogwarts_df.drop(
        [
        'name', 
        'surname',
        'is_griffindor',
        'is_hufflpuff',
        'is_ravenclaw'
        ], 
        axis=1).copy()
    X_data = data_full.drop('is_slitherin', axis=1)
    y = data_full.is_slitherin
    # Проводим исследование моделей
    slitherin_models = train_classifiers(data_full, X_data, y)
    score_testing_dataset(slitherin_models[5])

    Кирилл Малев — 0.09437856871661066
    Kirill Malev — 0.20820536334902712
    Гарри Поттер — 0.07550095601699099
    Harry Potter — 0.07683794773639624
    Северус Снейп — 0.9414529336862744
    Северус Снегг — 0.9293671807790949
    Severus Snape — 0.6576783576162999
    Том Реддл — 0.18577792617672767
    Tom Riddle — 0.8351835484058869
    Салазар Слизерин — 0.25930925139546795
    Salazar Slytherin — 0.24008788903854789

    Die Zahlen in dieser Version sehen subjektiv besser aus als in der Vergangenheit, sind aber für einen internen Perfektionisten nicht gut genug. Deshalb werden wir tiefer gehen und zur Produktbedeutung unserer Aufgabe zurückkehren: Sie müssen die wahrscheinlichste Fähigkeit vorhersagen, bei der der Held durch den Verteilungshut zugewiesen wird. Dies bedeutet, dass Sie Modelle für jede Fakultät trainieren müssen.



    >> from model_training import train_all_models
    # Обучаем модели для каждого факультета
    >> slitherin_models, griffindor_models, ravenclaw_models, hufflpuff_models = \
        train_all_models()

    Lange Ausgabe und multinomiale Regressionsergebnisse
    SVM Default Report
    Accuracy for SVM Default: 73.93
    ROC AUC for SVM Default: 0.53
    Tuned SVM Report
    Accuracy for Tuned SVM: 72.37
    ROC AUC for Tuned SVM: 0.50
    KNN Default Report
    Accuracy for KNN Default: 70.04
    ROC AUC for KNN Default: 0.58
    Tuned KNN Report
    Accuracy for Tuned KNN: 69.65
    ROC AUC for Tuned KNN: 0.58
    XGBoost Default Report
    Accuracy for XGBoost Default: 70.43
    ROC AUC for XGBoost Default: 0.54
    Tuned XGBoost Report
    Accuracy for Tuned XGBoost: 68.09
    ROC AUC for Tuned XGBoost: 0.56
    Random Forest Default Report
    Accuracy for Random Forest Default: 73.93
    ROC AUC for Random Forest Default: 0.62
    Tuned Random Forest Report
    Accuracy for Tuned Random Forest: 74.32
    ROC AUC for Tuned Random Forest: 0.54
    Extra Trees Default Report
    Accuracy for Extra Trees Default: 69.26
    ROC AUC for Extra Trees Default: 0.57
    Tuned Extra Trees Report
    Accuracy for Tuned Extra Trees: 73.54
    ROC AUC for Tuned Extra Trees: 0.55
    LGBM Default Report
    Accuracy for LGBM Default: 70.82
    ROC AUC for LGBM Default: 0.62
    Tuned LGBM Report
    Accuracy for Tuned LGBM: 74.71
    ROC AUC for Tuned LGBM: 0.53
    RGF Default Report
    Accuracy for RGF Default: 70.43
    ROC AUC for RGF Default: 0.58
    Tuned RGF Report
    Accuracy for Tuned RGF: 71.60
    ROC AUC for Tuned RGF: 0.60
    FRGF Default Report
    Accuracy for FRGF Default: 68.87
    ROC AUC for FRGF Default: 0.59
    Tuned FRGF Report
    Accuracy for Tuned FRGF: 69.26
    ROC AUC for Tuned FRGF: 0.59
    SVM Default Report
    Accuracy for SVM Default: 70.43
    ROC AUC for SVM Default: 0.50
    Tuned SVM Report
    Accuracy for Tuned SVM: 71.60
    ROC AUC for Tuned SVM: 0.50
    KNN Default Report
    Accuracy for KNN Default: 63.04
    ROC AUC for KNN Default: 0.49
    Tuned KNN Report
    Accuracy for Tuned KNN: 65.76
    ROC AUC for Tuned KNN: 0.50
    XGBoost Default Report
    Accuracy for XGBoost Default: 69.65
    ROC AUC for XGBoost Default: 0.54
    Tuned XGBoost Report
    Accuracy for Tuned XGBoost: 68.09
    ROC AUC for Tuned XGBoost: 0.50
    Random Forest Default Report
    Accuracy for Random Forest Default: 66.15
    ROC AUC for Random Forest Default: 0.51
    Tuned Random Forest Report
    Accuracy for Tuned Random Forest: 70.43
    ROC AUC for Tuned Random Forest: 0.50
    Extra Trees Default Report
    Accuracy for Extra Trees Default: 64.20
    ROC AUC for Extra Trees Default: 0.49
    Tuned Extra Trees Report
    Accuracy for Tuned Extra Trees: 70.82
    ROC AUC for Tuned Extra Trees: 0.51
    LGBM Default Report
    Accuracy for LGBM Default: 67.70
    ROC AUC for LGBM Default: 0.56
    Tuned LGBM Report
    Accuracy for Tuned LGBM: 70.82
    ROC AUC for Tuned LGBM: 0.50
    RGF Default Report
    Accuracy for RGF Default: 66.54
    ROC AUC for RGF Default: 0.52
    Tuned RGF Report
    Accuracy for Tuned RGF: 65.76
    ROC AUC for Tuned RGF: 0.53
    FRGF Default Report
    Accuracy for FRGF Default: 65.76
    ROC AUC for FRGF Default: 0.53
    Tuned FRGF Report
    Accuracy for Tuned FRGF: 69.65
    ROC AUC for Tuned FRGF: 0.52
    SVM Default Report
    Accuracy for SVM Default: 74.32
    ROC AUC for SVM Default: 0.50
    Tuned SVM Report
    Accuracy for Tuned SVM: 74.71
    ROC AUC for Tuned SVM: 0.51
    KNN Default Report
    Accuracy for KNN Default: 69.26
    ROC AUC for KNN Default: 0.48
    Tuned KNN Report
    Accuracy for Tuned KNN: 73.15
    ROC AUC for Tuned KNN: 0.49
    XGBoost Default Report
    Accuracy for XGBoost Default: 72.76
    ROC AUC for XGBoost Default: 0.49
    Tuned XGBoost Report
    Accuracy for Tuned XGBoost: 74.32
    ROC AUC for Tuned XGBoost: 0.50
    Random Forest Default Report
    Accuracy for Random Forest Default: 73.93
    ROC AUC for Random Forest Default: 0.52
    Tuned Random Forest Report
    Accuracy for Tuned Random Forest: 74.32
    ROC AUC for Tuned Random Forest: 0.50
    Extra Trees Default Report
    Accuracy for Extra Trees Default: 73.93
    ROC AUC for Extra Trees Default: 0.52
    Tuned Extra Trees Report
    Accuracy for Tuned Extra Trees: 73.93
    ROC AUC for Tuned Extra Trees: 0.50
    LGBM Default Report
    Accuracy for LGBM Default: 73.54
    ROC AUC for LGBM Default: 0.52
    Tuned LGBM Report
    Accuracy for Tuned LGBM: 74.32
    ROC AUC for Tuned LGBM: 0.50
    RGF Default Report
    Accuracy for RGF Default: 73.54
    ROC AUC for RGF Default: 0.51
    Tuned RGF Report
    Accuracy for Tuned RGF: 73.93
    ROC AUC for Tuned RGF: 0.50
    FRGF Default Report
    Accuracy for FRGF Default: 73.93
    ROC AUC for FRGF Default: 0.53
    Tuned FRGF Report
    Accuracy for Tuned FRGF: 73.93
    ROC AUC for Tuned FRGF: 0.50
    SVM Default Report
    Accuracy for SVM Default: 80.54
    ROC AUC for SVM Default: 0.50
    Tuned SVM Report
    Accuracy for Tuned SVM: 80.93
    ROC AUC for Tuned SVM: 0.52
    KNN Default Report
    Accuracy for KNN Default: 78.60
    ROC AUC for KNN Default: 0.50
    Tuned KNN Report
    Accuracy for Tuned KNN: 80.16
    ROC AUC for Tuned KNN: 0.51
    XGBoost Default Report
    Accuracy for XGBoost Default: 80.54
    ROC AUC for XGBoost Default: 0.50
    Tuned XGBoost Report
    Accuracy for Tuned XGBoost: 77.04
    ROC AUC for Tuned XGBoost: 0.52
    Random Forest Default Report
    Accuracy for Random Forest Default: 77.43
    ROC AUC for Random Forest Default: 0.49
    Tuned Random Forest Report
    Accuracy for Tuned Random Forest: 80.54
    ROC AUC for Tuned Random Forest: 0.50
    Extra Trees Default Report
    Accuracy for Extra Trees Default: 76.26
    ROC AUC for Extra Trees Default: 0.48
    Tuned Extra Trees Report
    Accuracy for Tuned Extra Trees: 78.60
    ROC AUC for Tuned Extra Trees: 0.50
    LGBM Default Report
    Accuracy for LGBM Default: 75.49
    ROC AUC for LGBM Default: 0.51
    Tuned LGBM Report
    Accuracy for Tuned LGBM: 80.54
    ROC AUC for Tuned LGBM: 0.50
    RGF Default Report
    Accuracy for RGF Default: 78.99
    ROC AUC for RGF Default: 0.52
    Tuned RGF Report
    Accuracy for Tuned RGF: 75.88
    ROC AUC for Tuned RGF: 0.55
    FRGF Default Report
    Accuracy for FRGF Default: 76.65
    ROC AUC for FRGF Default: 0.50
    # Респект тем читателям, которые открывают кат и смотрят на результаты

    from sklearn.linear_model import LogisticRegression
    clf = LogisticRegression(random_state=0, solver='lbfgs',  multi_class='multinomial') 
    hogwarts_df = load_processed_data_multi()
    # Оставляем только нужные колонки
    data_full = hogwarts_df.drop(
        [
        'name', 
        'surname',
        ], 
        axis=1).copy()
    X_data = data_full.drop('faculty', axis=1)
    y = data_full.faculty
    clf.fit(X_data, y)
    score_testing_dataset(clf)

    Кирилл Малев — [0.3602361  0.16166944 0.16771712 0.31037733]
    Kirill Malev — [0.47473072 0.16051924 0.13511385 0.22963619]
    Гарри Поттер — [0.38697926 0.19330242 0.17451052 0.2452078 ]
    Harry Potter — [0.40245098 0.16410043 0.16023278 0.27321581]
    Северус Снейп — [0.13197025 0.16438855 0.17739254 0.52624866]
    Северус Снегг — [0.17170203 0.1205678  0.14341742 0.56431275]
    Severus Snape — [0.15558044 0.21589378 0.17370406 0.45482172]
    Том Реддл — [0.39301231 0.07397324 0.1212741  0.41174035]
    Tom Riddle — [0.26623969 0.14194379 0.1728505  0.41896601]
    Салазар Слизерин — [0.24843037 0.21632736 0.21532696 0.3199153 ]
    Salazar Slytherin — [0.09359144 0.26735897 0.2742305  0.36481909]

    И confusion_matrix:


    confusion_matrix(clf.predict(X_data), y)

    array([[144,  68,  64,  78],
           [  8,   9,   8,   6],
           [ 22,  18,  31,  20],
           [ 77,  73,  78, 151]])

    def get_predctions_vector (models, person):
        predictions = [get_predictions_vector (model, person)[1] for model in models]
        return {
            'slitherin': predictions[0],
            'griffindor': predictions[1],
            'ravenclaw': predictions[2],
            'hufflpuff': predictions[3]
        }
    def score_testing_dataset (models):
        testing_dataset = [
                "Кирилл Малев", "Kirill Malev",
                "Гарри Поттер", "Harry Potter", 
                "Северус Снейп", "Северус Снегг","Severus Snape",
                "Том Реддл", "Tom Riddle", 
                "Салазар Слизерин", "Salazar Slytherin"]
        data = []
        for name in testing_dataset: 
            predictions = get_predctions_vector(models, name)
            predictions['name'] = name
            data.append(predictions)
        scoring_df = pd.DataFrame(data, 
                                  columns=['name', 
                                           'slitherin', 
                                           'griffindor', 
                                           'hufflpuff', 
                                           'ravenclaw'])
        return scoring_df
    #  Data Science — лучший выбор для тех, кто хочет работать с топ моделями
    top_models = [
        slitherin_models[3],
        griffindor_models[3], 
        ravenclaw_models[3], 
        hufflpuff_models[3]
    ]
    score_testing_dataset(top_models)

        name    slitherin   griffindor  hufflpuff   ravenclaw
    0   Кирилл Малев    0.349084    0.266909    0.110311    0.091045
    1   Kirill Malev    0.289914    0.376122    0.384986    0.103056
    2   Гарри Поттер    0.338258    0.400841    0.016668    0.124825
    3   Harry Potter    0.245377    0.357934    0.026287    0.154592
    4   Северус Снейп   0.917423    0.126997    0.176640    0.096570
    5   Северус Снегг   0.969693    0.106384    0.150146    0.082195
    6   Severus Snape   0.663732    0.259189    0.290252    0.074148
    7   Том Реддл   0.268466    0.579401    0.007900    0.083195
    8   Tom Riddle  0.639731    0.541184    0.084395    0.156245
    9   Салазар Слизерин    0.653595    0.147506    0.172940    0.137134
    10  Salazar Slytherin   0.647399    0.169964    0.095450    0.26126


    Wie aus dem Testdatensatz hervorgeht, Nicht alle Slytherins sind böseDer Hut ist manchmal falsch. Gleichzeitig ist die durchschnittliche ROC AUC etwas besser als 0,5. Um unerwünschte Fehler zu vermeiden, gibt es mehrere Möglichkeiten:


    • Geben Sie zusätzliche Funktionen ein.
    • Versuchen Sie, andere Algorithmen zu trainieren.
    • Einführung einer komplexen Verlustfunktion, die mehr Fehler bei der Verteilung von Schlüsselcharakteren bestraft;
    • Fügen Sie Quelldateien doppelte Namen hinzu, um ihnen mehr Gewicht zu verleihen.
    • Sammeln eines Datensatzes, anhand dessen eine Entscheidung ausgewählt wird, und Auswählen der Modelle, die dem Editor als endgültige Entscheidungen gefallen.

    Jede dieser Optionen eröffnet die Möglichkeit, Modelle neu zu trainieren und zu evaluieren. Da wir uns jedoch einig waren, dass wir es eilig haben, treffen wir eine vorsätzliche Entscheidung, um die besten XGBoost-Modelle mit den besten CV-Parametern zu wählen Produktion


    Es ist wichtig! Die oben diskutierten Modelle wurden nur auf 70% der Daten trainiert. Daher werden wir für den Einsatz in der Produktion 4 Modelle mit dem gesamten Datensatz neu trainieren und die Ergebnisse erneut auswerten.


    from model_training import train_production_models
    from xgboost import XGBClassifier
    best_models = []
    for i in range (0,4):
        best_models.append(XGBClassifier(base_score=0.5, booster='gbtree', colsample_bylevel=1,
               colsample_bytree=0.7, gamma=0, learning_rate=0.05, max_delta_step=0,
               max_depth=6, min_child_weight=11, missing=-999, n_estimators=1000,
               n_jobs=1, nthread=4, objective='binary:logistic', random_state=0,
               reg_alpha=0, reg_lambda=1, scale_pos_weight=1, seed=1337, silent=1,
               subsample=0.8))
    slitherin_model, griffindor_model, ravenclaw_model, hufflpuff_model = \
        train_production_models(best_models)
    top_models = slitherin_model, griffindor_model, ravenclaw_model, hufflpuff_model
    score_testing_dataset(top_models)

    name    slitherin   griffindor  hufflpuff   ravenclaw
    0   Кирилл Малев    0.273713    0.372337    0.065923    0.279577
    1   Kirill Malev    0.401603    0.761467    0.111068    0.023902
    2   Гарри Поттер    0.031540    0.616535    0.196342    0.217829
    3   Harry Potter    0.183760    0.422733    0.119393    0.173184
    4   Северус Снейп   0.945895    0.021788    0.209820    0.019449
    5   Северус Снегг   0.950932    0.088979    0.084131    0.012575
    6   Severus Snape   0.634035    0.088230    0.249871    0.036682
    7   Том Реддл   0.426440    0.431351    0.028444    0.083636
    8   Tom Riddle  0.816804    0.136530    0.069564    0.035500
    9   Салазар Слизерин    0.409634    0.213925    0.028631    0.252723
    10  Salazar Slytherin   0.824590    0.067910    0.111147    0.085710

    Wenn Sie sich diese Tabelle genau ansehen, können Sie feststellen, dass sich die Ergebnisse verbessert haben.


    Wir exportieren die resultierenden Modelle, damit sie später verwendet werden können, ohne den Prozess der Datenvorbereitung, Feature-Extraktion und Modellschulung zu wiederholen. Lassen Sie uns den meisten Saft behalten.


    import pickle
    pickle.dump(slitherin_model, open("../output/slitherin.xgbm", "wb"))
    pickle.dump(griffindor_model, open("../output/griffindor.xgbm", "wb"))
    pickle.dump(ravenclaw_model, open("../output/ravenclaw.xgbm", "wb"))
    pickle.dump(hufflpuff_model, open("../output/hufflpuff.xgbm", "wb"))

    Produktion


    Selbst das coolste und raffinierteste Modell wird nur dann davon profitieren, wenn die Leute es benutzen können. Und um das Licht überhaupt zu sehen, müssen Sie es bequem für den Endbenutzer verwenden.


    Der Endbenutzer eines ML-Modells ist häufig nicht der Endbenutzer des Dienstes, sondern der Entwickler, der ihn in das Produkt integriert. Auch wenn diese Rolle übernommen werden muss, sollte das Modell in eine komfortable Oberfläche gepackt werden. Daher erinnern wir uns, dass jeder Data Scientist ein kleines Backend ist und tauchen in die Backend-Entwicklung ein.


    Grundvoraussetzungen für die Integrationsaufgabe:


    • Das Modell sollte als separater Dienst arbeiten.
    • Akzeptieren Sie Daten in Form einer JSON-Anfrage und geben Sie eine Antwort in Form von JSON.
    • Das Modell sollte in jeder Umgebung ohne lange Einstellungen einsatzbereit sein.

    Natürlich wird die Lösung in einen Docker-Container gepackt, damit der Entwickler keine zusätzlichen Pakete installieren und die Python-Umgebung optimieren muss. Wir werden die Entscheidung treffen, welche die Daten akzeptiert und die Antwort auf die Flasche zurücksenden.


    Erste Option
    from __future__ import print_function # In python 2.7
    import os
    import subprocess
    import json
    import re
    from flask import Flask, request, jsonify
    from inspect import getmembers, ismethod
    import numpy as npb
    import pandas as pd
    import math
    import os
    import pickle
    import xgboost as xgb
    import sys
    from letter import Letter
    from talking_hat import *
    from sklearn.ensemble import RandomForestClassifier
    import warnings
    def prod_predict_classes_for_name (full_name):
        featurized_person = parse_line_to_hogwarts_df(full_name)
        person_df = pd.DataFrame(featurized_person,
            columns=[
             'name', 
             'surname', 
             'is_english',
             'name_starts_with_vowel', 
             'name_starts_with_consonant',
             'name_ends_with_vowel', 
             'name_ends_with_consonant',
             'name_length', 
             'name_vowels_count',
             'name_double_vowels_count',
             'name_consonant_count',
             'name_double_consonant_count',
             'name_paired_count',
             'name_deaf_count',
             'name_sonorus_count',
             'surname_starts_with_vowel', 
             'surname_starts_with_consonant',
             'surname_ends_with_vowel', 
             'surname_ends_with_consonant',
             'surname_length', 
             'surname_vowels_count',
             'surname_double_vowels_count',
             'surname_consonant_count',
             'surname_double_consonant_count',
             'surname_paired_count',
             'surname_deaf_count',
             'surname_sonorus_count',
            ],
                                 index=[0]
        )
        slitherin_model =  pickle.load(open("models/slitherin.xgbm", "rb"))
        griffindor_model = pickle.load(open("models/griffindor.xgbm", "rb"))
        ravenclaw_model = pickle.load(open("models/ravenclaw.xgbm", "rb"))
        hufflpuff_model = pickle.load(open("models/hufflpuff.xgbm", "rb"))
        predictions =  get_predctions_vector([
                            slitherin_model,
                            griffindor_model,
                            ravenclaw_model,
                            hufflpuff_model
                            ], 
                          person_df.drop(['name', 'surname'], axis=1))
        return {
            'slitherin': float(predictions[0][1]),
            'griffindor': float(predictions[1][1]),
            'ravenclaw': float(predictions[2][1]),
            'hufflpuff': float(predictions[3][1])
        }
    def predict(params):
        fullname = params['fullname']
        print(params)
        return prod_predict_classes_for_name(fullname)
    def create_app():
        app = Flask(__name__)
        functions_list = [predict]
        @app.route('/<func_name>', methods=['POST'])
        def api_root(func_name):
            for function in functions_list:
                if function.__name__ == func_name:
                    try:
                        json_req_data = request.get_json()
                        if json_req_data:
                            res = function(json_req_data)
                        else:
                            return jsonify({"error": "error in receiving the json input"})
                    except Exception as e:
                        data = {
                            "error": "error while running the function"
                        }
                        if hasattr(e, 'message'):
                            data['message'] = e.message
                        elif len(e.args) >= 1:
                            data['message'] = e.args[0]
                        return jsonify(data)
                    return jsonify({"success": True, "result": res})
            output_string = 'function: %s not found' % func_name
            return jsonify({"error": output_string})
        return app
    if __name__ == '__main__':
        app = create_app()
        app.run(host='0.0.0.0')

    Dockerfile:


    FROM datmo/python-base:cpu-py35
    # Используем python3-wheel, чтобы не тратить время на сборку пакетов
    RUN apt-get update; apt-get install -y python3-pip python3-numpy python3-scipy python3-wheel
    ADD requirements.txt /
    RUN pip3 install -r /requirements.txt
    RUN mkdir /code;mkdir /code/models
    COPY ./python_api.py ./talking_hat.py ./letter.py ./request.py /code/
    COPY ./models/* /code/models/
    WORKDIR /code
    CMD python3 /code/python_api.py

    Das Modell wird sehr einfach sein:


    docker build -t talking_hat . && docker rm talking_hat && docker run --name talking_hat -p 5000:5000 talking_hat

    Serienmodelle testen


    Die Lösung hat einen Nachteil: Das Skript verbringt jedes Mal Zeit mit dem Entladen und Laden des Modells aus dem Speicher. Beheben Sie dieses Problem, aber messen Sie zuerst die Leistung dieser Lösung mit dem Apache-Benchmark . Es ist in der Tat kurzsichtig, das Modell zu testen, aber nicht die endgültige Lösung. Testen ist unser Alles.


    $ ab -p data.json -T application/json -c 50 -n 10000 http://0.0.0.0:5000/predict

    Ab Ausgabe
    This is ApacheBench, Version 2.3 <$Revision: 1807734 $>
    Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
    Licensed to The Apache Software Foundation, http://www.apache.org/
    Benchmarking 0.0.0.0 (be patient)
    Completed 1000 requests
    Completed 2000 requests
    Completed 3000 requests
    Completed 4000 requests
    Completed 5000 requests
    Completed 6000 requests
    Completed 7000 requests
    Completed 8000 requests
    Completed 9000 requests
    Completed 10000 requests
    Finished 10000 requests
    Server Software:        Werkzeug/0.14.1
    Server Hostname:        0.0.0.0
    Server Port:            5000
    Document Path:          /predict
    Document Length:        141 bytes
    Concurrency Level:      50
    Time taken for tests:   238.552 seconds
    Complete requests:      10000
    Failed requests:        0
    Total transferred:      2880000 bytes
    Total body sent:        1800000
    HTML transferred:       1410000 bytes
    Requests per second:    41.92 [#/sec] (mean)
    Time per request:       1192.758 [ms] (mean)
    Time per request:       23.855 [ms] (mean, across all concurrent requests)
    Transfer rate:          11.79 [Kbytes/sec] received
                            7.37 kb/s sent
                            19.16 kb/s total
    Connection Times (ms)
                  min  mean[+/-sd] median   max
    Connect:        0    0   0.1      0       3
    Processing:   199 1191 352.5   1128    3352
    Waiting:      198 1190 352.5   1127    3351
    Total:        202 1191 352.5   1128    3352
    Percentage of the requests served within a certain time (ms)
      50%   1128
      66%   1277
      75%   1378
      80%   1451
      90%   1668
      95%   1860
      98%   2096
      99%   2260
     100%   3352 (longest request)

    Jetzt werden wir die Lösung für die Variante geben, wenn das Modell ständig in den Speicher geladen wird:


    def prod_predict_classes_for_name (full_name):
        <...>
        predictions =  get_predctions_vector([
                            app.slitherin_model,
                            app.griffindor_model,
                            app.ravenclaw_model,
                            app.hufflpuff_model
                            ], 
                          person_df.drop(['name', 'surname'], axis=1))
        return {
            'slitherin': float(predictions[0][1]),
            'griffindor': float(predictions[1][1]),
            'ravenclaw': float(predictions[2][1]),
            'hufflpuff': float(predictions[3][1])
        }
    def create_app():
        <...>
        with app.app_context():
            app.slitherin_model =  pickle.load(open("models/slitherin.xgbm", "rb"))
            app.griffindor_model = pickle.load(open("models/griffindor.xgbm", "rb"))
            app.ravenclaw_model = pickle.load(open("models/ravenclaw.xgbm", "rb"))
            app.hufflpuff_model = pickle.load(open("models/hufflpuff.xgbm", "rb"))
        return app

    Und messen Sie die Testergebnisse:


    $ docker build -t talking_hat . && docker rm talking_hat && docker run --name talking_hat -p 5000:5000 talking_hat
    $ ab -p data.json -T application/json -c 50 -n 10000 http://0.0.0.0:5000/predict

    Ab Ausgabe
    This is ApacheBench, Version 2.3 <$Revision: 1807734 $>
    Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
    Licensed to The Apache Software Foundation, http://www.apache.org/
    Benchmarking 0.0.0.0 (be patient)
    Completed 1000 requests
    Completed 2000 requests
    Completed 3000 requests
    Completed 4000 requests
    Completed 5000 requests
    Completed 6000 requests
    Completed 7000 requests
    Completed 8000 requests
    Completed 9000 requests
    Completed 10000 requests
    Finished 10000 requests
    Server Software:        Werkzeug/0.14.1
    Server Hostname:        0.0.0.0
    Server Port:            5000
    Document Path:          /predict
    Document Length:        141 bytes
    Concurrency Level:      50
    Time taken for tests:   219.812 seconds
    Complete requests:      10000
    Failed requests:        3
       (Connect: 0, Receive: 0, Length: 3, Exceptions: 0)
    Total transferred:      2879997 bytes
    Total body sent:        1800000
    HTML transferred:       1409997 bytes
    Requests per second:    45.49 [#/sec] (mean)
    Time per request:       1099.062 [ms] (mean)
    Time per request:       21.981 [ms] (mean, across all concurrent requests)
    Transfer rate:          12.79 [Kbytes/sec] received
                            8.00 kb/s sent
                            20.79 kb/s total
    Connection Times (ms)
                  min  mean[+/-sd] median   max
    Connect:        0    0   0.1      0       2
    Processing:   235 1098 335.2   1035    3464
    Waiting:      235 1097 335.2   1034    3462
    Total:        238 1098 335.2   1035    3464
    Percentage of the requests served within a certain time (ms)
      50%   1035
      66%   1176
      75%   1278
      80%   1349
      90%   1541
      95%   1736
      98%   1967
      99%   2141
     100%   3464 (longest request)

    Ist fertig Erhielt eine kleine Steigerung. In dieser Form kann das Modell in Form eines Repositorys angegeben werden, das bei Bedarf sehr schnell in eine beliebige Site eingebettet werden kann.


    Fazit


    Tatsächlich haben wir als Teil des Artikels eine kleine Studie erstellt, deren Ergebnis ein praktikables Definitionsmodell für die Hogwarts-Fakultät nach Benutzernamen war. Die resultierende Lösung kann zur Erstellung von Werbeseiten oder einfach als Lehrbeispiel verwendet werden.


    Natürlich kann die Lösung weiter verbessert werden:


    • Aus Sicht des Feature Engineerings kann eine phonetische Suche verwendet werden ( einleitender Artikel zu Habré), insbesondere der Soundex- Algorithmus zur Bestimmung des Klangs eines Namens.
    • Sie können den wunderbaren Artikel im PyTorch-Blog verwenden und das wiederkehrende neuronale Netzwerk verwenden, um Namen zu klassifizieren. Dieser Artikel ist fast fertig für unsere Aufgaben, er berücksichtigt die Definition des Ursprungslandes des Namens, dh es werden die gleichen Namensklassifizierungsprobleme gelöst.
    • Sie können vom Synchronkolben zum asynchronen Quart wechseln , was theoretisch zur Lösung unseres Problems geeignet erscheint, wodurch die Lösung noch widerstandsfähiger gegen hohe Lasten wird.
    • Fügen Sie dem Repository Bot-Carts oder eine Demoseite hinzu, damit die Lösung einfacher getestet werden kann.

    Abhängig von den Wünschen und der Kritik können Sie zur Lösung dieses Bildungsproblems zurückkehren, um zu demonstrieren, wie Sie das Modell weiter verbessern können. Danke fürs Lesen!


    Dieser Artikel wäre ohne die Open Data Science-Community, die eine große Anzahl russischsprachiger Datenanalysespezialisten zusammenbringt, nicht veröffentlicht worden.