3.3. Anpassen der Entscheidungsschwelle für Klassenprädiktion#
Klassifikation lässt sich am besten in zwei Teile aufteilen:
das statistische Problem des Lernens eines Modells zur Vorhersage, idealerweise, von Klassenwahrscheinlichkeiten;
das Entscheidungsproblem, basierend auf diesen Wahrscheinlichkeitsvorhersagen konkrete Maßnahmen zu ergreifen.
Nehmen wir ein einfaches Beispiel aus der Wettervorhersage: Der erste Punkt bezieht sich auf die Frage „Wie hoch ist die Wahrscheinlichkeit, dass es morgen regnet?“, während sich der zweite Punkt auf die Frage bezieht: „Sollte ich morgen einen Regenschirm mitnehmen?“.
Wenn es um die scikit-learn API geht, wird der erste Punkt durch die Bereitstellung von Scores mittels predict_proba oder decision_function behandelt. Ersteres gibt bedingte Wahrscheinlichkeitsschätzungen \(P(y|X)\) für jede Klasse zurück, letzteres gibt einen Entscheidungsscore für jede Klasse zurück.
Die Entscheidung, die den Labels entspricht, wird mit predict erzielt. Bei der binären Klassifikation wird dann eine Entscheidungsregel oder Aktion durch Schwellenwertbildung der Scores definiert, was zur Vorhersage eines einzelnen Klassenlabels für jede Stichprobe führt. Bei der binären Klassifikation in scikit-learn werden die Vorhersagen für Klassenlabels durch fest kodierte Grenzwertregeln erzielt: Eine positive Klasse wird vorhergesagt, wenn die bedingte Wahrscheinlichkeit \(P(y|X)\) größer als 0,5 ist (erhalten mit predict_proba) oder wenn der Entscheidungsscore größer als 0 ist (erhalten mit decision_function).
Hier zeigen wir ein Beispiel, das die Beziehung zwischen bedingten Wahrscheinlichkeitsschätzungen \(P(y|X)\) und Klassenlabels verdeutlicht.
>>> from sklearn.datasets import make_classification
>>> from sklearn.tree import DecisionTreeClassifier
>>> X, y = make_classification(random_state=0)
>>> classifier = DecisionTreeClassifier(max_depth=2, random_state=0).fit(X, y)
>>> classifier.predict_proba(X[:4])
array([[0.94 , 0.06 ],
[0.94 , 0.06 ],
[0.0416, 0.9583],
[0.0416, 0.9583]])
>>> classifier.predict(X[:4])
array([0, 0, 1, 1])
Obwohl diese fest kodierten Regeln auf den ersten Blick als Standardverhalten vernünftig erscheinen mögen, sind sie für die meisten Anwendungsfälle höchstwahrscheinlich nicht ideal. Lassen Sie uns dies anhand eines Beispiels veranschaulichen.
Stellen Sie sich ein Szenario vor, in dem ein prädiktives Modell zur Unterstützung von Ärzten bei der Erkennung von Tumoren eingesetzt wird. In diesem Umfeld sind Ärzte höchstwahrscheinlich daran interessiert, alle Patienten mit Krebs zu identifizieren und keinen Patienten mit Krebs zu übersehen, damit sie ihnen die richtige Behandlung zukommen lassen können. Mit anderen Worten, Ärzte legen Wert auf eine hohe Recall-Rate. Dieser Fokus auf Recall geht natürlich mit dem Kompromiss von potenziell mehr falsch-positiven Vorhersagen einher, was die Präzision des Modells reduziert. Das ist ein Risiko, das Ärzte einzugehen bereit sind, da die Kosten eines übersehenen Krebsfalls weitaus höher sind als die Kosten weiterer diagnostischer Tests. Folglich kann es, wenn es darum geht zu entscheiden, ob ein Patient als Krebsfall eingestuft wird oder nicht, vorteilhafter sein, ihn als Krebspositiv einzustufen, wenn die bedingte Wahrscheinlichkeitsschätzung deutlich unter 0,5 liegt.
3.3.1. Nachträgliches Anpassen der Entscheidungsschwelle#
Eine Lösung für das im Einleitungsteil dargestellte Problem ist die Anpassung der Entscheidungsschwelle des Klassifikators nach dem Trainieren des Modells. TunedThresholdClassifierCV passt diese Schwelle mittels interner Kreuzvalidierung an. Die optimale Schwelle wird ausgewählt, um eine gegebene Metrik zu maximieren.
Das folgende Bild veranschaulicht die Anpassung der Entscheidungsschwelle für einen Gradient Boosting-Klassifikator. Während die Vanilla- und die angepassten Klassifikatoren die gleichen predict_proba-Ausgaben und somit die gleichen Receiver Operating Characteristic (ROC)- und Precision-Recall-Kurven liefern, unterscheiden sich die Klassenlabel-Vorhersagen aufgrund der angepassten Entscheidungsschwelle. Der Vanilla-Klassifikator sagt die interessante Klasse bei einer bedingten Wahrscheinlichkeit größer als 0,5 voraus, während der angepasste Klassifikator die interessante Klasse bei einer sehr niedrigen Wahrscheinlichkeit (ungefähr 0,02) vorhersagt. Diese Entscheidungsschwelle optimiert eine vom Unternehmen (in diesem Fall einer Versicherungsgesellschaft) definierte Nutzmetrik.
3.3.1.1. Optionen zur Anpassung der Entscheidungsschwelle#
Die Entscheidungsschwelle kann über verschiedene Strategien angepasst werden, die durch den Parameter scoring gesteuert werden.
Eine Möglichkeit, die Schwelle anzupassen, ist die Maximierung einer vordefinierten scikit-learn-Metrik. Diese Metriken können durch Aufruf der Funktion get_scorer_names abgerufen werden. Standardmäßig wird die balancierte Genauigkeit als Metrik verwendet, aber beachten Sie, dass man für seinen Anwendungsfall eine sinnvolle Metrik wählen sollte.
Hinweis
Es ist wichtig zu beachten, dass diese Metriken Standardparameter haben, insbesondere das Label der interessierenden Klasse (d. h. pos_label). Wenn dieses Label für Ihre Anwendung nicht das richtige ist, müssen Sie einen Score definieren und das richtige pos_label (und zusätzliche Parameter) mithilfe von make_scorer übergeben. Beziehen Sie sich auf Callable Scorers, um Informationen zur Definition Ihrer eigenen Scoring-Funktion zu erhalten. Wir zeigen beispielsweise, wie die Information an den Score übergeben wird, dass das interessierende Label 0 ist, wenn die f1_score maximiert wird.
>>> from sklearn.linear_model import LogisticRegression
>>> from sklearn.model_selection import TunedThresholdClassifierCV
>>> from sklearn.metrics import make_scorer, f1_score
>>> X, y = make_classification(
... n_samples=1_000, weights=[0.1, 0.9], random_state=0)
>>> pos_label = 0
>>> scorer = make_scorer(f1_score, pos_label=pos_label)
>>> base_model = LogisticRegression()
>>> model = TunedThresholdClassifierCV(base_model, scoring=scorer)
>>> scorer(model.fit(X, y), X, y)
0.88
>>> # compare it with the internal score found by cross-validation
>>> model.best_score_
np.float64(0.86)
3.3.1.2. Wichtige Hinweise zur internen Kreuzvalidierung#
Standardmäßig verwendet TunedThresholdClassifierCV eine 5-fache stratifizierte Kreuzvalidierung zur Anpassung der Entscheidungsschwelle. Der Parameter cv ermöglicht die Steuerung der Kreuzvalidierungsstrategie. Es ist möglich, die Kreuzvalidierung zu umgehen, indem cv="prefit" gesetzt und ein trainierter Klassifikator bereitgestellt wird. In diesem Fall wird die Entscheidungsschwelle auf den Daten, die an die fit-Methode übergeben werden, angepasst.
Sie sollten jedoch bei der Verwendung dieser Option äußerst vorsichtig sein. Sie sollten niemals dieselben Daten zum Trainieren des Klassifikators und zum Anpassen der Entscheidungsschwelle verwenden, um das Risiko von Overfitting zu vermeiden. Weitere Einzelheiten finden Sie im folgenden Beispielabschnitt (siehe Überlegungen zur Modell-Nachoptimierung und Kreuzvalidierung). Wenn Sie begrenzte Ressourcen haben, sollten Sie eine Gleitkommazahl für cv verwenden, um auf eine interne einzelne Train-Test-Aufteilung zu beschränken.
Die Option cv="prefit" sollte nur verwendet werden, wenn der bereitgestellte Klassifikator bereits trainiert wurde und Sie nur die beste Entscheidungsschwelle anhand eines neuen Validierungsdatensatzes ermitteln möchten.
3.3.1.3. Manuelles Festlegen der Entscheidungsschwelle#
Die vorherigen Abschnitte diskutierten Strategien zur Ermittlung einer optimalen Entscheidungsschwelle. Es ist auch möglich, die Entscheidungsschwelle manuell mithilfe der Klasse FixedThresholdClassifier festzulegen. Falls Sie das Modell beim Aufruf von fit nicht neu trainieren möchten, umschließen Sie Ihren Unterestimator mit einem FrozenEstimator und verwenden Sie FixedThresholdClassifier(FrozenEstimator(estimator), ...).
3.3.1.4. Beispiele#
Siehe das Beispiel mit dem Titel Nachträgliches Anpassen des Grenzwerts der Entscheidungsfunktion, um Einblicke in das nachträgliche Anpassen der Entscheidungsschwelle zu erhalten.
Siehe das Beispiel mit dem Titel Nachträgliches Anpassen der Entscheidungsschwelle für kostenempfindliches Lernen, um mehr über kostenempfindliches Lernen und die Anpassung der Entscheidungsschwelle zu erfahren.