Читать книгу Praxiseinstieg Machine Learning mit Scikit-Learn, Keras und TensorFlow - Aurélien Géron - Страница 80
Bessere Auswertung mittels Kreuzvalidierung
ОглавлениеWir könnten den Entscheidungsbaum evaluieren, indem wir den Trainingsdatensatz mit der Funktion train_test_split() in einen kleineren Trainingsdatensatz und einen Validierungsdatensatz aufteilen, dann das Modell mit dem kleineren Trainingsdatensatz trainieren und schließlich mit dem Validierungsdatensatz auswerten. Dies macht ein wenig Arbeit, ist aber nicht schwer und funktioniert recht gut.
Eine hervorragende Alternative dazu ist die in Scikit-Learn eingebaute k-fache Kreuzvalidierung. Der folgende Code spaltet den Trainingsdatensatz zufällig in zehn unterschiedliche Teilmengen, genannt Folds, auf. Anschließend trainiert und evaluiert er den Entscheidungsbaum zehnmal hintereinander, wobei jedes Mal ein anderer Fold zur Evaluierung genutzt wird, während auf den übrigen neun Folds trainiert wird. Das Ergebnis ist ein Array mit zehn Scores aus der Evaluierung:
from sklearn.model_selection import cross_val_score
scores = cross_val_score(tree_reg, housing_prepared, housing_labels,
scoring="neg_mean_squared_error", cv=10)
tree_rmse_scores = np.sqrt(-scores)
Die Kreuzvalidierung in Scikit-Learn erwartet eine Nutzenfunktion (größer ist besser) anstelle einer Kostenfunktion (kleiner ist besser). Daher ist die Scoring-Funktion das Gegenteil des MSE (also ein negativer Wert). Deshalb steht im Code der Ausdruck -scores vor dem Berechnen der Quadratwurzel. |
Betrachten wir das Ergebnis:
>>> def display_scores(scores):
... print("Scores:", scores)
... print("Mittelwert:", scores.mean())
... print("Standardabweichung:", scores.std())
...
>>> display_scores(tree_rmse_scores)
Scores: [70194.33680785 66855.16363941 72432.58244769 70758.73896782
71115.88230639 75585.14172901 70262.86139133 70273.6325285
75366.87952553 71231.65726027]
Mittelwert: 71407.68766037929
Standardabweichung: 2439.4345041191004
Nun steht der Entscheidungsbaum nicht mehr so gut da wie zuvor. Tatsächlich scheint er schlechter als das lineare Regressionsmodell abzuschneiden! Beachten Sie, dass wir mit der Kreuzvalidierung nicht nur eine Schätzung der Leistung unseres Modells erhalten, sondern auch eine Angabe darüber, wie präzise diese Schätzung ist (d.h. die Standardabweichung). Der Entscheidungsbaum hat einen RMSE von etwa 71407, ±2439. Nur mit einem Validierungsdatensatz würden Sie diese Information nicht erhalten. Allerdings erfordert die Kreuzvalidierung, dass das Modell mehrmals trainiert wird. Deshalb ist sie nicht immer praktikabel.
Berechnen wir, um auf Nummer sicher zu gehen, die gleichen Scores für das lineare Regressionsmodell:
>>> lin_scores = cross_val_score(lin_reg, housing_prepared, housing_labels,
... scoring="neg_mean_squared_error", cv=10)
...
>>> lin_rmse_scores = np.sqrt(-lin_scores)
>>> display_scores(lin_rmse_scores)
Scores: [66782.73843989 66960.118071 70347.95244419 74739.57052552
68031.13388938 71193.84183426 64969.63056405 68281.61137997
71552.91566558 67665.10082067]
Mittelwert: 69052.46136345083
Standardabweichung: 2731.674001798348
Unsere Vermutung war richtig: Das Overfitting im Entscheidungsbaum ist so stark, dass dieses Modell ungenauer ist als die lineare Regression.
Probieren wir noch ein letztes Modell aus: den RandomForestRegressor. Wie wir in Kapitel 7 sehen werden, trainiert ein Random Forest viele Entscheidungsbäume auf zufällig ausgewählten Teilmengen der Merkmale und mittelt deren Vorhersagen. Ein Modell aus vielen anderen Modellen zusammenzusetzen, nennt man Ensemble Learning. Es ist oft eine gute Möglichkeit, ML-Algorithmen noch besser zu nutzen. Wir werden uns mit dem Code nicht groß beschäftigen, da er fast der gleiche ist wie bei den anderen beiden Modellen:
>>> from sklearn.ensemble import RandomForestRegressor
>>> forest_reg = RandomForestRegressor()
>>> forest_reg.fit(housing_prepared, housing_labels)
>>> [...]
>>> forest_rmse
18603.515021376355
>>> display_scores(forest_rmse_scores)
Scores: [49519.80364233 47461.9115823 50029.02762854 52325.28068953
49308.39426421 53446.37892622 48634.8036574 47585.73832311
53490.10699751 50021.5852922 ]
Mittelwert: 50182.303100336096
Standardabweichung: 2097.0810550985693
Wow, das ist viel besser: Random Forests wirken sehr vielversprechend. Allerdings ist der Score auf dem Trainingsdatensatz noch immer viel geringer als auf den Validierungsdatensätzen. Dies deutet darauf hin, dass das Modell die Trainingsdaten noch immer overfittet. Gegenmaßnahmen zum Overfitting sind, das Modell zu vereinfachen, Restriktionen einzuführen (es zu regularisieren) oder deutlich mehr Trainingsdaten zu beschaffen. Bevor Sie sich aber eingehender mit Random Forests beschäftigen, sollten Sie mehr Modelle aus anderen Familien von Machine-Learning-Algorithmen ausprobieren (mehrere Support Vector Machines mit unterschiedlichen Kernels, ein neuronales Netz und so weiter), ohne jedoch zu viel Zeit mit dem Einstellen der Hyperparameter zu verbringen. Das Ziel ist, eine engere Auswahl (zwei bis fünf) der vielversprechendsten Modelle zu treffen.
Sie sollten alle Modelle, mit denen Sie experimentieren, abspeichern, sodass Sie später zu jedem beliebigen Modell zurückkehren können. Stellen Sie sicher, dass Sie sowohl die Hyperparameter als auch die trainierten Parameter abspeichern, ebenso die Scores der Kreuzvalidierung und eventuell sogar die Vorhersagen. Damit können Sie leichter Vergleiche der Scores und der Arten der Fehler zwischen unterschiedlichen Modellen ziehen. Sie können in Scikit-Learn erstellte Modelle mit dem Python-Modul pickle oder der Bibliothek joblib speichern, wobei Letztere große NumPy-Arrays effizienter serialisiert: import joblib joblib.dump(my_model, "my_model.pkl") # und später ... my_model_loaded = joblib.load("my_model.pkl") |