Wir machen ein maschinelles Lernprojekt in Python. Teil 2

Ursprünglicher Autor: William Koehrsen
  • Übersetzung
  • Tutorial


Übersetzung Ein vollständiger Durchgang zum maschinellen Lernen in Python: Teil 2 Das

Zusammenstellen aller Teile eines maschinellen Lernprojekts kann schwierig sein. In dieser Artikelserie werden wir alle Phasen der Implementierung des maschinellen Lernprozesses anhand realer Daten durchlaufen und herausfinden, wie die verschiedenen Techniken miteinander kombiniert werden.

Im ersten Artikel haben wir die Daten bereinigt und strukturiert, eine explorative Analyse durchgeführt, eine Reihe von Attributen zur Verwendung im Modell gesammelt und eine Basis für die Bewertung der Ergebnisse festgelegt. Mithilfe dieses Artikels lernen wir, wie Sie in Python implementieren und mehrere Modelle für maschinelles Lernen vergleichen, eine hyperparametrische Optimierung durchführen, um das beste Modell zu optimieren, und die Leistung des endgültigen Modells anhand eines Testdatensatzes bewerten.

Der gesamte Projektcode befindet sich auf GitHub , und hier ist das zweite Notizbuch, das sich auf den aktuellen Artikel bezieht. Sie können den Code beliebig verwenden und ändern!

Modellbewertung und -auswahl


Anmerkung: Wir arbeiten an einer kontrollierten Regressionsaufgabe und verwenden die Energieinformationen für Gebäude in New York , um ein Modell zu erstellen, das vorhersagt, welchen Energy Star Score ein bestimmtes Gebäude erhalten wird. Wir sind sowohl an der Genauigkeit der Prognose als auch an der Interpretierbarkeit des Modells interessiert.

Heute können Sie aus den vielen verfügbaren Modellen für maschinelles Lernen auswählen , und diese Fülle kann einschüchternd sein. Natürlich gibt es im Netzwerk vergleichende Bewertungen , die Ihnen bei der Auswahl eines Algorithmus helfen, aber ich ziehe es vor, einige davon auszuprobieren und herauszufinden, welcher besser ist. Maschinelles Lernen basiert größtenteils eher auf empirischen als auf theoretischen Ergebnissen und in der PraxisEs ist unmöglich im Voraus zu verstehen, welches Modell genauer ist .

Es wird normalerweise empfohlen, mit einfachen, interpretierbaren Modellen wie der linearen Regression zu beginnen. Wenn die Ergebnisse nicht zufriedenstellend sind, fahren Sie mit komplexeren, aber normalerweise genaueren Methoden fort. Diese Grafik (sehr anti-wissenschaftlich) zeigt die Beziehung zwischen der Genauigkeit und Interpretierbarkeit einiger Algorithmen:


Interpretierbarkeit und Genauigkeit ( Quelle ).

Wir werden fünf Modelle mit unterschiedlichem Komplexitätsgrad bewerten:

  • Lineare Regression.
  • Die Methode der k-nächsten Nachbarn.
  • "Zufälliger Wald."
  • Gradientenverstärkung.
  • Methode der Unterstützungsvektoren.

Wir werden nicht den theoretischen Apparat dieser Modelle betrachten, sondern ihre Implementierung. Wenn Sie sich für Theorie interessieren, lesen Sie eine Einführung in das statistische Lernen (kostenlos erhältlich) oder das praktische maschinelle Lernen mit Scikit-Learn und TensorFlow . In beiden Büchern wird die Theorie perfekt erklärt und die Wirksamkeit der Verwendung der genannten Methoden in den Sprachen R bzw. Python gezeigt.

Geben Sie die fehlenden Werte ein


Obwohl wir beim Löschen der Daten die Spalten verworfen haben, in denen mehr als die Hälfte der Werte fehlen, haben wir immer noch viele Werte. Modelle für maschinelles Lernen können nicht mit fehlenden Daten arbeiten, daher müssen wir sie ausfüllen .

Zuerst betrachten wir die Daten und erinnern uns, wie sie aussehen:

import pandas as pd
import numpy as np
# Read in data into dataframes 
train_features = pd.read_csv('data/training_features.csv')
test_features = pd.read_csv('data/testing_features.csv')
train_labels = pd.read_csv('data/training_labels.csv')
test_labels = pd.read_csv('data/testing_labels.csv')
Training Feature Size:  (6622, 64)
Testing Feature Size:   (2839, 64)
Training Labels Size:   (6622, 1)
Testing Labels Size:    (2839, 1)

Jeder NaNWert ist ein fehlender Datensatz in den Daten. Sie können sie auf verschiedene Arten füllen , und wir verwenden die relativ einfache Median-Imputationsmethode, bei der die fehlenden Daten durch die Durchschnittswerte für die entsprechenden Spalten ersetzt werden.

Im folgenden Code erstellen wir ein Scikit-Learn- Objekt Imputermit einer Medianstrategie. Dann trainieren wir es auf den Trainingsdaten (mit imputer.fit) und wenden es an, um die fehlenden Werte in den Trainings- und Testsätzen (mit imputer.transform) auszufüllen . Das heißt, die Datensätze, die in den Testdaten fehlen , werden mit dem entsprechenden Medianwert aus den Trainingsdaten gefüllt .

Wir führen das Füllen durch und trainieren das Modell nicht so, wie es ist, um das Problem des Verlusts von Testdaten zu vermeiden, wenn Informationen aus dem Testdatensatz in das Training einfließen.

# Create an imputer object with a median filling strategy
imputer = Imputer(strategy='median')
# Train on the training features
imputer.fit(train_features)
# Transform both training data and testing data
X = imputer.transform(train_features)
X_test = imputer.transform(test_features)
Missing values in training features:  0
Missing values in testing features:   0

Jetzt sind alle Werte gefüllt, es gibt keine Lücken.

Feature-Skalierung


Die Skalierung ist der allgemeine Prozess zum Ändern des Bereichs eines Merkmals. Dies ist ein notwendiger Schritt , da Vorzeichen in verschiedenen Einheiten gemessen werden, was bedeutet, dass sie unterschiedliche Bereiche abdecken. Dies verzerrt die Ergebnisse von Algorithmen wie der Support-Vektor- Methode und der k-Nearest-Neighbour-Methode, die die Abstände zwischen den Messungen berücksichtigen, erheblich . Durch Skalierung können Sie dies vermeiden. Obwohl Methoden wie lineare Regression und „Random Forest“ keine Skalierung von Features erfordern, ist es besser, diesen Schritt beim Vergleich mehrerer Algorithmen nicht zu vernachlässigen.

Wir skalieren mit jedem Attribut auf einen Bereich von 0 bis 1. Wir nehmen alle Werte des Attributs, wählen das Minimum aus und dividieren es durch die Differenz zwischen Maximum und Minimum (Bereich). Diese Skalierungsmethode wird oft als Normalisierung bezeichnet, und der andere Hauptweg ist die Standardisierung .

Dieser Prozess ist einfach manuell zu implementieren, daher verwenden wir das Objekt MinMaxScalervon Scikit-Learn. Der Code für diese Methode ist identisch mit dem Code zum Ausfüllen der fehlenden Werte. Anstelle des Einfügens wird nur die Skalierung verwendet. Denken Sie daran, dass wir das Modell nur im Trainingssatz lernen und dann alle Daten transformieren.

# Create the scaler object with a range of 0-1
scaler = MinMaxScaler(feature_range=(0, 1))
# Fit on the training data
scaler.fit(X)
# Transform both the training and testing data
X = scaler.transform(X)
X_test = scaler.transform(X_test)

Jetzt hat jedes Attribut einen Mindestwert von 0 und einen Höchstwert von 1. Das Ausfüllen der fehlenden Werte und die Skalierung der Attribute - diese beiden Stufen werden in fast jedem maschinellen Lernprozess benötigt.

Wir implementieren maschinelle Lernmodelle in Scikit-Learn


Nach all den Vorarbeiten ist das Erstellen, Trainieren und Ausführen von Modellen relativ einfach. Wir werden die Scikit-Learn- Bibliothek in Python verwenden , die wunderschön dokumentiert ist und über eine ausgefeilte Syntax zum Erstellen von Modellen verfügt. Indem Sie lernen, wie Sie in Scikit-Learn ein Modell erstellen, können Sie schnell alle Arten von Algorithmen implementieren.

Wir werden den Prozess des Erstellens, Trainings ( .fit) und Testens ( .predict) unter Verwendung von Gradientenverstärkung veranschaulichen:

from sklearn.ensemble import GradientBoostingRegressor
# Create the model
gradient_boosted = GradientBoostingRegressor()
# Fit the model on the training data
gradient_boosted.fit(X, y)
# Make predictions on the test data
predictions = gradient_boosted.predict(X_test)
# Evaluate the model
mae = np.mean(abs(predictions - y_test))
print('Gradient Boosted Performance on the test set: MAE = %0.4f' % mae)
Gradient Boosted Performance on the test set: MAE = 10.0132

Nur eine Codezeile zum Erstellen, Trainieren und Testen. Um andere Modelle zu erstellen, verwenden wir dieselbe Syntax und ändern nur den Namen des Algorithmus.



Um Modelle objektiv zu bewerten, haben wir den Basispegel anhand des Medianwerts des Ziels berechnet und 24,5 erhalten. Die Ergebnisse waren viel besser, sodass unser Problem durch maschinelles Lernen gelöst werden kann.

In unserem Fall erwies sich die Gradientenverstärkung (MAE = 10.013) als etwas besser als die "zufällige Gesamtstruktur" (10.014 MAE). Obwohl diese Ergebnisse nicht als ganz ehrlich angesehen werden können, verwenden wir für Hyperparameter meistens die Standardwerte. Die Modellleistung hängt stark von diesen Einstellungen ab, insbesondere bei der Support-Vektor-Methode. Basierend auf diesen Ergebnissen werden wir jedoch die Gradientenverstärkung wählen und beginnen, sie zu optimieren.

Hyperparametrische Modelloptimierung


Nachdem Sie ein Modell ausgewählt haben, können Sie es für die zu lösende Aufgabe optimieren, indem Sie die Hyperparameter anpassen.

Aber lassen Sie uns zunächst verstehen, was Hyperparameter sind und wie sie sich von gewöhnlichen Parametern unterscheiden .

  • Die Hyperparameter des Modells können als Einstellungen des Algorithmus betrachtet werden, die wir vor Beginn des Trainings festgelegt haben. Beispielsweise ist der Hyperparameter die Anzahl der Bäume in der "zufälligen Gesamtstruktur" oder die Anzahl der Nachbarn in der Methode der k-nächsten Nachbarn.
  • Modellparameter - was sie während des Trainings lernt, zum Beispiel Gewichte in linearer Regression.

Durch die Steuerung des Hyperparameters beeinflussen wir die Ergebnisse des Modells und verändern das Gleichgewicht zwischen Untererziehung und Umschulung . Unter Lernen versteht man eine Situation, in der das Modell nicht komplex genug ist (es hat zu wenig Freiheitsgrade), um die Entsprechung von Zeichen und Zielen zu untersuchen. Ein untertrainiertes Modell weist eine hohe Vorspannung auf, die durch Komplikation des Modells korrigiert werden kann.

Umschulung ist eine Situation, in der sich das Modell im Wesentlichen an die Trainingsdaten erinnert. Das umgeschulte Modell weist eine hohe Varianz auf, die angepasst werden kann, indem die Komplexität des Modells durch Regularisierung begrenzt wird. Sowohl unter- als auch umgeschulte Modelle können die Testdaten nicht gut verallgemeinern.

Die Schwierigkeit bei der Auswahl der richtigen Hyperparameter besteht darin, dass für jede Aufgabe ein eindeutiger optimaler Satz vorhanden ist. Daher können Sie die besten Einstellungen nur auswählen, indem Sie verschiedene Kombinationen für das neue Dataset ausprobieren. Glücklicherweise verfügt Scikit-Learn über eine Reihe von Methoden, mit denen Sie Hyperparameter effektiv bewerten können. Darüber hinaus versuchen Projekte wie TPOT , die Suche nach Hyperparametern mithilfe von Ansätzen wie der genetischen Programmierung zu optimieren . In diesem Artikel beschränken wir uns auf die Verwendung von Scikit-Learn.

Überprüfen Sie die zufällige Suche


Lassen Sie uns eine Hyperparameter-Optimierungsmethode implementieren, die als zufällige Kreuzvalidierungssuchen bezeichnet wird:

  • Zufallssuche - eine Technik zur Auswahl von Hyperparametern. Wir definieren ein Raster und wählen dann zufällig verschiedene Kombinationen daraus aus, im Gegensatz zur Rastersuche, bei der wir jede Kombination nacheinander ausprobieren. Die Zufallssuche funktioniert übrigens fast genauso gut wie die Rastersuche , ist aber viel schneller.
  • Durch Gegenprüfung kann die ausgewählte Kombination von Hyperparametern bewertet werden. Anstatt die Daten in Trainings- und Testsätze aufzuteilen, wodurch die für das Training verfügbare Datenmenge reduziert wird, verwenden wir die K-Block-Kreuzvalidierung (K-Fold Cross Validation). Dazu teilen wir die Trainingsdaten in k Blöcke auf und führen dann den iterativen Prozess aus, bei dem wir zuerst das Modell auf k-1 Blöcken trainieren und dann das Ergebnis vergleichen, wenn wir auf dem k-ten Block lernen. Wir werden den Vorgang k-mal wiederholen und am Ende den durchschnittlichen Fehlerwert für jede Iteration erhalten. Dies wird die endgültige Bewertung sein.

Hier ist eine klare Darstellung der Kreuzvalidierung von k-Blöcken für k = 5:



Der gesamte Prozess der Zufallssuche mit Kreuzvalidierung sieht folgendermaßen aus:

  1. Wir setzen ein Gitter von Hyperparametern.
  2. Wählen Sie zufällig eine Kombination von Hyperparametern aus.
  3. Erstellen Sie mit dieser Kombination ein Modell.
  4. Wir bewerten das Ergebnis des Modells mithilfe der K-Block-Kreuzvalidierung.
  5. Wir entscheiden, welche Hyperparameter das beste Ergebnis liefern.

Natürlich geschieht dies alles nicht manuell, sondern mit Hilfe RandomizedSearchCVvon Scikit-Learn!

Kleiner Exkurs: Gradientenverstärkungsmethoden


Wir werden ein Gradienten-Boost-basiertes Regressionsmodell verwenden. Dies ist eine kollektive Methode, dh das Modell besteht aus zahlreichen „schwachen Lernenden“, in diesem Fall aus separaten Entscheidungsbäumen. Wenn die Schüler in parallelen Algorithmen wie „Random Forest“ lernen und dann das Vorhersageergebnis durch Abstimmung ausgewählt wird , werden die Schüler in Boosting-Algorithmen wie Gradient Boosting nacheinander geschult, und jeder von ihnen „konzentriert“ sich auf Fehler, die von Vorgängern gemacht wurden.

In den letzten Jahren sind Boosting-Algorithmen populär geworden und gewinnen häufig bei Wettbewerben für maschinelles Lernen. Gradientenverstärkung- Eine der Implementierungen, bei denen Gradient Descent verwendet wird, um die Kosten der Funktion zu minimieren. Die Implementierung der Gradientenverstärkung in Scikit-Learn wird als nicht so effektiv angesehen wie in anderen Bibliotheken, beispielsweise in XGBoost , funktioniert jedoch gut bei kleinen Datensätzen und liefert ziemlich genaue Prognosen.

Zurück zur hyperparametrischen Einstellung


Bei der Regression mit Gradientenverstärkung müssen viele Hyperparameter konfiguriert werden. Einzelheiten finden Sie in der Scikit-Learn-Dokumentation. Wir werden optimieren:

  • loss: Minimierung der Verlustfunktion;
  • n_estimators: Anzahl der verwendeten schwachen Entscheidungsbäume (Entscheidungsbäume);
  • max_depth: maximale Tiefe jedes Entscheidungsbaums;
  • min_samples_leaf: die Mindestanzahl von Beispielen, die sich im Blattknoten des Entscheidungsbaums befinden sollten;
  • min_samples_split: die Mindestanzahl von Beispielen, die zum Trennen des Entscheidungsbaumknotens erforderlich sind;
  • max_features: Die maximale Anzahl von Features, die zum Trennen von Knoten verwendet werden.

Ich bin mir nicht sicher, ob jemand wirklich versteht, wie das alles funktioniert, und der einzige Weg, die beste Kombination zu finden, besteht darin, verschiedene Optionen auszuprobieren.

In diesem Code erstellen wir ein Raster von Hyperparametern, erstellen dann ein Objekt RandomizedSearchCVund suchen es mithilfe einer 4-Block-Kreuzvalidierung für 25 verschiedene Kombinationen von Hyperparametern:

# Loss function to be optimized
loss = ['ls', 'lad', 'huber']
# Number of trees used in the boosting process
n_estimators = [100, 500, 900, 1100, 1500]
# Maximum depth of each tree
max_depth = [2, 3, 5, 10, 15]
# Minimum number of samples per leaf
min_samples_leaf = [1, 2, 4, 6, 8]
# Minimum number of samples to split a node
min_samples_split = [2, 4, 6, 10]
# Maximum number of features to consider for making splits
max_features = ['auto', 'sqrt', 'log2', None]
# Define the grid of hyperparameters to search
hyperparameter_grid = {'loss': loss,
    'n_estimators': n_estimators,
    'max_depth': max_depth,
    'min_samples_leaf': min_samples_leaf,
    'min_samples_split': min_samples_split,
    'max_features': max_features}
# Create the model to use for hyperparameter tuning
model = GradientBoostingRegressor(random_state = 42)
# Set up the random search with 4-fold cross validation
random_cv = RandomizedSearchCV(estimator=model,
    param_distributions=hyperparameter_grid,
    cv=4, n_iter=25, 
    scoring = 'neg_mean_absolute_error',
    n_jobs = -1, verbose = 1, 
    return_train_score = True,
    random_state=42)
# Fit on the training data
random_cv.fit(X, y) After performing the search, we can inspect the RandomizedSearchCV object to find the best model:
# Find the best combination of settings
random_cv.best_estimator_
GradientBoostingRegressor(loss='lad', max_depth=5,
    max_features=None,
    min_samples_leaf=6,
    min_samples_split=6,
    n_estimators=500)

Sie können diese Ergebnisse für eine Rastersuche verwenden, indem Sie Parameter für das Raster auswählen, die nahe an diesen optimalen Werten liegen. Eine weitere Abstimmung dürfte das Modell jedoch nicht wesentlich verbessern. Es gibt eine allgemeine Regel: Die kompetente Konstruktion von Merkmalen hat einen viel größeren Einfluss auf die Genauigkeit des Modells als die teuerste Hyperparametereinstellung. Dies ist das Gesetz zur Verringerung der Rentabilität in Bezug auf maschinelles Lernen : Das Entwerfen von Attributen bietet die höchste Rendite, und hyperparametrisches Tuning bringt nur bescheidene Vorteile.

Um die Anzahl der Schätzer (Entscheidungsbäume) zu ändern und gleichzeitig die Werte anderer Hyperparameter beizubehalten, kann ein Experiment durchgeführt werden, das die Rolle dieser Einstellung demonstriert. Die Implementierung ist hier angegeben , aber hier ist das Ergebnis:



Mit zunehmender Anzahl der vom Modell verwendeten Bäume nimmt die Fehlerquote beim Training und Testen ab. Lernfehler nehmen jedoch viel schneller ab, und infolgedessen wird das Modell umgeschult: Es zeigt hervorragende Ergebnisse bei Trainingsdaten, funktioniert jedoch schlechter bei Testdaten.

Bei Testdaten nimmt die Genauigkeit immer ab (da das Modell die richtigen Antworten für den Trainingsdatensatz sieht), aber ein signifikanter Rückgang weist auf eine Umschulung hin . Dieses Problem kann gelöst werden, indem die Menge der Trainingsdaten erhöht oder die Komplexität des Modells mithilfe von Hyperparametern verringert wird . Hier werden wir nicht auf Hyperparameter eingehen, aber ich empfehle Ihnen, immer auf das Problem der Umschulung zu achten.

Für unser endgültiges Modell werden 800 Bewerter herangezogen, da dies die niedrigste Fehlerquote bei der Kreuzvalidierung ergibt. Testen Sie jetzt das Modell!

Bewertung anhand von Testdaten


Als Verantwortliche haben wir dafür gesorgt, dass unser Modell während des Trainings in keiner Weise Zugang zu Testdaten erhielt. Daher können wir die Genauigkeit bei der Arbeit mit Testdaten als Modellqualitätsindikator verwenden, wenn diese für reale Aufgaben zugelassen sind.

Wir geben die Modelltestdaten ein und berechnen den Fehler. Hier ist ein Vergleich der Ergebnisse des Standardalgorithmus zur Erhöhung des Gradienten und unseres benutzerdefinierten Modells:

# Make predictions on the test set using default and final model
default_pred = default_model.predict(X_test)
final_pred = final_model.predict(X_test)
Default model performance on the test set: MAE = 10.0118.
Final model performance on the test set: MAE = 9.0446.

Durch hyperparametrische Abstimmung konnte die Modellgenauigkeit um etwa 10% verbessert werden. Je nach Situation kann dies eine erhebliche Verbesserung sein, die jedoch viel Zeit in Anspruch nimmt.

Sie können die Trainingsdauer für beide Modelle mit dem Magic-Team %timeitin Jupyter Notebooks vergleichen. Messen Sie zunächst die Standarddauer des Modells:

%%timeit -n 1 -r 5
default_model.fit(X, y)
1.09 s ± 153 ms per loop (mean ± std. dev. of 5 runs, 1 loop each)

Eine Sekunde zum Lernen ist sehr anständig. Aber das getunte Modell ist nicht so schnell:

%%timeit -n 1 -r 5
final_model.fit(X, y)
12.1 s ± 1.33 s per loop (mean ± std. dev. of 5 runs, 1 loop each)

Diese Situation verdeutlicht den grundlegenden Aspekt des maschinellen Lernens: Es geht um Kompromisse . Es ist ständig notwendig, ein Gleichgewicht zwischen Genauigkeit und Interpretierbarkeit, zwischen Verschiebung und Streuung , zwischen Genauigkeit und Betriebszeit usw. zu wählen . Die richtige Kombination wird vollständig von der spezifischen Aufgabe bestimmt. In unserem Fall ist eine 12-fache Verlängerung der Arbeitsdauer relativ gesehen groß, aber absolut gesehen unbedeutend.

Wir haben die endgültigen Prognoseergebnisse erhalten. Analysieren wir sie nun und stellen fest, ob es erkennbare Abweichungen gibt. Links ist ein Diagramm der Dichte der vorhergesagten und realen Werte, rechts ein Histogramm des Fehlers:



Die Vorhersage des Modells wiederholt die Verteilung der realen Werte gut, während sich der Dichtepeak in den Trainingsdaten näher am Medianwert (66) befindet als am realen Dichtepeak (etwa 100). Fehler haben eine fast normale Verteilung, obwohl es mehrere große negative Werte gibt, wenn sich die Modellprognose stark von den realen Daten unterscheidet. Im nächsten Artikel werden wir uns die Interpretation der Ergebnisse genauer ansehen.

Fazit


In diesem Artikel haben wir verschiedene Phasen der Lösung des Problems des maschinellen Lernens untersucht:

  • Fehlende Werte und Skalierungsfunktionen ausfüllen.
  • Auswertung und Vergleich der Ergebnisse mehrerer Modelle.
  • Hyperparametrische Abstimmung mit zufälliger Rastersuche und Kreuzvalidierung.
  • Bewertung des besten Modells anhand von Testdaten.

Die Ergebnisse zeigen, dass wir maschinelles Lernen verwenden können, um den Energy Star Score basierend auf verfügbaren Statistiken vorherzusagen. Mit Hilfe der Gradientenverstärkung wurde ein Fehler von 9,1 bei den Testdaten erreicht. Hyperparametrisches Tuning kann die Ergebnisse erheblich verbessern, jedoch auf Kosten einer signifikanten Verlangsamung. Dies ist einer von vielen Kompromissen, die beim maschinellen Lernen berücksichtigt werden müssen.

Im nächsten Artikel werden wir versuchen herauszufinden, wie unser Modell funktioniert. Wir werden uns auch die Hauptfaktoren ansehen, die den Energy Star Score beeinflussen. Wenn wir wissen, dass das Modell genau ist, werden wir versuchen zu verstehen, warum es dies vorhersagt und was uns dies über das Problem selbst sagt.

Jetzt auch beliebt: