Читать книгу Praxiseinstieg Machine Learning mit Scikit-Learn, Keras und TensorFlow - Aurélien Géron - Страница 103

Klassifikatoren mit mehreren Kategorien

Оглавление

Während binäre Klassifikatoren zwischen zwei Kategorien unterscheiden, können Klassifikatoren mit mehreren Kategorien (auch multinomiale Klassifikatoren genannt) mehr als zwei Kategorien unterscheiden.

Einige Algorithmen (wie SGD-Klassifikatoren, Random-Forest-Klassifikatoren oder naive Bayes-Klassifikatoren) sind in der Lage, direkt mehrere Kategorien zu berücksichtigen. Andere (wie logistische Regression oder Support-Vector-Machine-Klassifikatoren) sind stets binäre Klassifikatoren. Es gibt jedoch einige Strategien, mit denen sich mit mehreren binären Klassifikatoren mehrere Kategorien zuordnen lassen.

Sie könnten beispielsweise ein System zum Einteilen der Bilder von Ziffern in zehn Kategorien (von 0 bis 9) entwickeln, indem Sie zehn binäre Klassifikatoren trainieren, einen für jede Ziffer (also einen 0-Detektor, einen 1-Detektor, einen 2-Detektor und so weiter). Wenn Sie anschließend ein Bild klassifizieren möchten, ermitteln Sie für jeden dieser Klassifikatoren den Entscheidungsscore und wählen die Kategorie aus, deren Klassifikator den höchsten Score lieferte. Dies bezeichnet man als One-versus-the-Rest-(OvR-)Strategie (oder One-versus-All).

Eine weitere Strategie ist, einen binären Klassifikator pro Zahlenpaar zu trainieren: einen zum Unterscheiden von 0 und 1, einen weiteren zum Unterscheiden von 0 und 2, einen für 1 und 2 und so weiter. Dies bezeichnet man als One-versus-One-(OvO-)Strategie. Wenn es N Kategorien gibt, müssen Sie N × (N – 1) / 2 Klassifikatoren trainieren. Bei der MNIST-Aufgabe müsste man also 45 binäre Klassifikatoren trainieren! Wenn Sie ein Bild klassifizieren möchten, müssten Sie das Bild alle 45 Klassifikatoren durchlaufen lassen und prüfen, welche Kategorie am häufigsten vorkommt. Der Hauptvorteil von OvO ist, dass jeder Klassifikator nur auf dem Teil der Trainingsdaten mit den beiden zu unterscheidenden Kategorien trainiert werden muss.

Einige Algorithmen (wie Support-Vector-Machine-Klassifikatoren) skalieren schlecht mit der Größe des Trainingsdatensatzes. Bei diesen ist also OvO zu bevorzugen, weil sich viele Klassifikatoren mit kleinen Trainingsdatensätzen schneller trainieren lassen als wenige Klassifikatoren auf großen Trainingsdatensätzen. Bei den meisten binären Klassifikationsalgorithmen ist jedoch OvR vorzuziehen.

Scikit-Learn erkennt, wenn Sie einen binären Klassifikationsalgorithmus für eine Aufgabe mit mehreren Kategorien einsetzen, und verwendet abhängig vom Algorithmus automatisch OvR oder OvO. Probieren wir das mit einem SVM-Klassifikator (siehe Kapitel 5) und der Klasse sklearn.svm.SVC:

>>> from sklearn.svm import SVC

>>> svm_clf = SVC()

>>> svm_clf.fit(X_train, y_train) # y_train, nicht y_train_5

>>> svm_clf.predict([some_digit])

array([5], dtype=uint8)

Das war leicht! Der Code trainiert den SVC auf den Trainingsdaten mit den ursprünglichen Zielkategorien von 0 bis 9 (y_train) anstatt mit den Zielkategorien 5-gegen-den-Rest (y_train_5). Anschließend wird eine Vorhersage getroffen (in diesem Fall eine richtige). Im Hintergrund nutzt Scikit-Learn die OvO-Strategie: Es trainiert 45 binäre Klassifikatoren, ermittelt deren Entscheidungswerte für das Bild und wählt die Kategorie aus, die die meisten Duelle gewonnen hat.

Rufen Sie die Methode decision_function() auf, werden Sie sehen, dass zehn Scores pro Instanz zurückgegeben werden (statt nur einer). Das ist ein Score pro Kategorie:

>>> some_digit_scores = svm_clf.decision_function([some_digit])

>>> some_digit_scores

array([[ 2.92492871, 7.02307409, 3.93648529, 0.90117363, 5.96945908,

9.5 , 1.90718593, 8.02755089, -0.13202708, 4.94216947]])

Der höchste Wert ist in der Tat derjenige für die Kategorie 5:

>>> np.argmax(some_digit_scores)

5

>>> svm_clf.classes_

array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=uint8)

>>> svm_clf.classes_[5]

5

Beim Trainieren eines Klassifikators wird die Liste der Zielkategorien im Attribut classes_ nach Werten sortiert gespeichert. In diesem Fall entspricht der Index jeder Kategorie im Array classes_ bequemerweise der Kategorie selbst (beispielsweise ist die Kategorie beim Index 5 auch die Kategorie 5), aber normalerweise ist dies nicht so.

Wenn Sie Scikit-Learn dazu bringen möchten, das One-versus-One- oder das One-versus-the-Rest-Verfahren zu verwenden, nutzen Sie dazu die Klassen OneVs OneClassifier bzw. OneVsRestClassifier. Erstellen Sie einfach eine Instanz, der Sie im Konstruktor einen Klassifikator übergeben (es muss nicht einmal ein binärer Klassifikator sein). Der folgende Code erzeugt beispielsweise einen Klassifikator mit mehreren Kategorien mithilfe der OvR-Strategie und einem SVC:

>>> from sklearn.multiclass import OneVsRestClassifier

>>> ovr_clf = OneVsRestClassifier(SVC())

>>> ovr_clf.fit(X_train, y_train)

>>> ovr_clf.predict([some_digit])

array([5], dtype=uint8)

>>> len(ovr_clf.estimators_)

10

Einen SGDClassifier (oder einen RandomForestClassifier) zu verwenden, ist genauso einfach:

>>> sgd_clf.fit(X_train, y_train)

>>> sgd_clf.predict([some_digit])

array([5], dtype=uint8)

Diesmal musste Scikit-Learn weder OvR noch OvO anwenden, da SGD-Klassifikatoren Datenpunkte direkt mehreren Kategorien zuordnen können. Die Methode decision_function() liefert nun einen Wert pro Kategorie zurück. Schauen wir uns den Score an, den der SGD-Klassifikator jeder Kategorie zugewiesen hat:

>>> sgd_clf.decision_function([some_digit])

array([[-15955.22628, -38080.96296, -13326.66695, 573.52692, -17680.68466,

2412.53175, -25526.86498, -12290.15705, -7946.05205, -10631.35889]])

Sie sehen auch, dass sich der Klassifikator seiner Vorhersage sehr sicher ist: So gut wie alle Scores sind deutlich negativ, aber die Kategorie 5 besitzt einen Score von 2412,5. Bei Kategorie 3 ist sich das Modell nicht sicher, da sie einen Score von 573,5 hat. Diese Klassifikatoren sollten wir nun natürlich auch auswerten. Wie gewöhnlich setzen wir die Kreuzvalidierung ein. Beurteilen wir die Genauigkeit des SGD-Classifier mit der Funktion cross_val_score():

>>> cross_val_score(sgd_clf, X_train, y_train, cv=3, scoring="accuracy")

array([0.8489802 , 0.87129356, 0.86988048])

In sämtlichen Test-Folds erhalten wir mehr als 84%. Mit einem zufälligen Klassifikator hätten wir eine Genauigkeit von 10% erhalten. Dies ist also kein schlechtes Ergebnis. Es geht aber noch viel besser. Beispielsweise erhöht ein einfaches Skalieren der Eingabedaten (wie in Kapitel 2 besprochen) die Genauigkeit auf über 89%:

>>> from sklearn.preprocessing import StandardScaler

>>> scaler = StandardScaler()

>>> X_train_scaled = scaler.fit_transform(X_train.astype(np.float64))

>>> cross_val_score(sgd_clf, X_train_scaled, y_train, cv=3, scoring="accuracy")

array([0.89707059, 0.8960948 , 0.90693604])

Praxiseinstieg Machine Learning mit Scikit-Learn, Keras und TensorFlow

Подняться наверх