4. Metadata Routing#

Hinweis

Die Metadata Routing API ist experimentell und noch nicht für alle Estimators implementiert. Weitere Informationen finden Sie in der Liste der unterstützten und nicht unterstützten Modelle. Sie kann sich ohne den üblichen Deprecation-Zyklus ändern. Standardmäßig ist diese Funktion nicht aktiviert. Sie können sie aktivieren, indem Sie das Flag enable_metadata_routing auf True setzen.

>>> import sklearn
>>> sklearn.set_config(enable_metadata_routing=True)

Beachten Sie, dass die in diesem Dokument eingeführten Methoden und Anforderungen nur dann relevant sind, wenn Sie Metadaten (z. B. sample_weight) an einen Estimator übergeben möchten. Wenn Sie nur X und y und keine anderen Parameter/Metadaten an Methoden wie fit, transform usw. übergeben, müssen Sie nichts weiter einstellen.

Diese Anleitung zeigt, wie Metadaten in scikit-learn zwischen Objekten weitergeleitet und übergeben werden können. Wenn Sie einen scikit-learn-kompatiblen Estimator oder Meta-Estimator entwickeln, können Sie sich unseren Entwicklerleitfaden ansehen: Metadata Routing.

Metadaten sind Daten, die ein Estimator, ein Scorer oder ein CV-Splitter berücksichtigt, wenn der Benutzer sie explizit als Parameter übergibt. Zum Beispiel akzeptiert KMeans sample_weight in seiner fit()-Methode und berücksichtigt diese zur Berechnung seiner Zentren. classes werden von einigen Klassifikatoren konsumiert und groups werden in einigen Splittern verwendet, aber alle Daten, die außer X und y an die Methoden eines Objekts übergeben werden, können als Metadaten betrachtet werden. Vor scikit-learn Version 1.3 gab es keine einheitliche API zum Übergeben von Metadaten dieser Art, wenn diese Objekte in Verbindung mit anderen Objekten verwendet wurden, z. B. ein Scorer, der sample_weight innerhalb von GridSearchCV akzeptiert.

Mit der Metadata Routing API können wir Metadaten an Estimators, Scorer und CV-Splitter mithilfe von Meta-Estimators (wie Pipeline oder GridSearchCV) oder Funktionen wie cross_validate weiterleiten, die Daten an andere Objekte routen. Um Metadaten an eine Methode wie fit oder score zu übergeben, muss das Objekt, das die Metadaten konsumiert, diese *anfordern*. Dies geschieht über set_{method}_request()-Methoden, wobei {method} durch den Namen der Methode ersetzt wird, die die Metadaten anfordert. Estimators, die die Metadaten in ihrer fit()-Methode verwenden, würden zum Beispiel set_fit_request() verwenden, und Scorer würden set_score_request() verwenden. Diese Methoden ermöglichen es uns, anzugeben, welche Metadaten angefordert werden sollen, z. B. set_fit_request(sample_weight=True).

Für gruppierte Splitter wie GroupKFold wird standardmäßig ein groups-Parameter angefordert. Dies wird am besten durch die folgenden Beispiele verdeutlicht.

4.1. Anwendungsbeispiele#

Hier stellen wir einige Beispiele für gängige Anwendungsfälle vor. Unser Ziel ist es, sample_weight und groups über cross_validate weiterzuleiten, das die Metadaten an LogisticRegressionCV und einen benutzerdefinierten Scorer, der mit make_scorer erstellt wurde, weiterleitet. Beide *können* die Metadaten in ihren Methoden verwenden. In diesen Beispielen möchten wir individuell festlegen, ob die Metadaten innerhalb der verschiedenen Konsumenten verwendet werden sollen.

Die Beispiele in diesem Abschnitt erfordern die folgenden Importe und Daten

>>> import numpy as np
>>> from sklearn.metrics import make_scorer, accuracy_score
>>> from sklearn.linear_model import LogisticRegressionCV, LogisticRegression
>>> from sklearn.model_selection import cross_validate, GridSearchCV, GroupKFold
>>> from sklearn.feature_selection import SelectKBest
>>> from sklearn.pipeline import make_pipeline
>>> n_samples, n_features = 100, 4
>>> rng = np.random.RandomState(42)
>>> X = rng.rand(n_samples, n_features)
>>> y = rng.randint(0, 2, size=n_samples)
>>> my_groups = rng.randint(0, 10, size=n_samples)
>>> my_weights = rng.rand(n_samples)
>>> my_other_weights = rng.rand(n_samples)

4.1.1. Gewichtete Bewertung und Anpassung#

Der intern in LogisticRegressionCV verwendete Splitter, GroupKFold, fordert standardmäßig groups an. Wir müssen jedoch explizit sample_weight für sich und unseren benutzerdefinierten Scorer anfordern, indem wir sample_weight=True in der set_fit_request()-Methode von LogisticRegressionCV und in der set_score_request()-Methode von make_scorer festlegen. Beide Konsumenten wissen, wie sie sample_weight in ihren fit()- oder score()-Methoden verwenden. Wir können die Metadaten dann in cross_validate übergeben, die sie an alle aktiven Konsumenten weiterleitet.

>>> weighted_acc = make_scorer(accuracy_score).set_score_request(sample_weight=True)
>>> lr = LogisticRegressionCV(
...     cv=GroupKFold(),
...     scoring=weighted_acc,
...     use_legacy_attributes=False,
... ).set_fit_request(sample_weight=True)
>>> cv_results = cross_validate(
...     lr,
...     X,
...     y,
...     params={"sample_weight": my_weights, "groups": my_groups},
...     cv=GroupKFold(),
...     scoring=weighted_acc,
... )

Beachten Sie, dass cross_validate in diesem Beispiel my_weights sowohl an den Scorer als auch an LogisticRegressionCV weiterleitet.

Wenn wir sample_weight in den Parametern von cross_validate übergeben würden, aber kein Objekt zum Anfordern festlegen, würde UnsetMetadataPassedError ausgelöst, was uns darauf hinweist, dass wir explizit festlegen müssen, wohin es weitergeleitet werden soll. Dasselbe gilt, wenn params={"sample_weights": my_weights, ...} übergeben würde (beachten Sie den Tippfehler, d. h. weights anstelle von weight), da sample_weights von keinem seiner zugrunde liegenden Objekte angefordert wurde.

4.1.2. Gewichtete Bewertung und ungewichtete Anpassung#

Beim Übergeben von Metadaten wie sample_weight an einen Router (Meta-Estimators oder Routing-Funktion) müssen alle sample_weight Konsumenten entweder explizit Gewichtungen anfordern oder explizit nicht anfordern (d. h. True oder False). Daher müssen wir, um eine ungewichtete Anpassung durchzuführen, LogisticRegressionCV so konfigurieren, dass es keine Stichprobengewichtungen anfordert, damit cross_validate die Gewichtungen nicht weitergibt.

>>> weighted_acc = make_scorer(accuracy_score).set_score_request(sample_weight=True)
>>> lr = LogisticRegressionCV(
...     cv=GroupKFold(), scoring=weighted_acc, use_legacy_attributes=False
... ).set_fit_request(sample_weight=False)
>>> cv_results = cross_validate(
...     lr,
...     X,
...     y,
...     cv=GroupKFold(),
...     params={"sample_weight": my_weights, "groups": my_groups},
...     scoring=weighted_acc,
... )

Wenn linear_model.LogisticRegressionCV.set_fit_request nicht aufgerufen worden wäre, würde cross_validate einen Fehler auslösen, da sample_weight übergeben wird, aber LogisticRegressionCV nicht explizit zur Erkennung der Gewichtungen konfiguriert wäre.

4.1.3. Ungewichtete Merkmalsauswahl#

Das Weiterleiten von Metadaten ist nur möglich, wenn die Methode des Objekts die Metadaten zu verwenden weiß, was in den meisten Fällen bedeutet, dass sie als expliziter Parameter vorhanden sind. Nur dann können wir Anforderungswerte für Metadaten mit set_fit_request(sample_weight=True), zum Beispiel, festlegen. Dies macht das Objekt zu einem Konsumenten.

Im Gegensatz zu LogisticRegressionCV kann SelectKBest keine Gewichtungen verarbeiten, und daher wird kein Anforderungswert für sample_weight auf seiner Instanz festgelegt und sample_weight wird nicht an ihn weitergeleitet.

>>> weighted_acc = make_scorer(accuracy_score).set_score_request(sample_weight=True)
>>> lr = LogisticRegressionCV(
...     cv=GroupKFold(), scoring=weighted_acc, use_legacy_attributes=False
... ).set_fit_request(sample_weight=True)
>>> sel = SelectKBest(k=2)
>>> pipe = make_pipeline(sel, lr)
>>> cv_results = cross_validate(
...     pipe,
...     X,
...     y,
...     cv=GroupKFold(),
...     params={"sample_weight": my_weights, "groups": my_groups},
...     scoring=weighted_acc,
... )

4.1.4. Unterschiedliche Bewertungsgewichte und Anpassungsgewichte#

Obwohl make_scorer und LogisticRegressionCV beide den Schlüssel sample_weight erwarten, können wir Aliase verwenden, um unterschiedliche Gewichtungen an verschiedene Konsumenten zu übergeben. In diesem Beispiel übergeben wir scoring_weight an den Scorer und fitting_weight an LogisticRegressionCV.

>>> weighted_acc = make_scorer(accuracy_score).set_score_request(
...    sample_weight="scoring_weight"
... )
>>> lr = LogisticRegressionCV(
...     cv=GroupKFold(), scoring=weighted_acc, use_legacy_attributes=False
... ).set_fit_request(sample_weight="fitting_weight")
>>> cv_results = cross_validate(
...     lr,
...     X,
...     y,
...     cv=GroupKFold(),
...     params={
...         "scoring_weight": my_weights,
...         "fitting_weight": my_other_weights,
...         "groups": my_groups,
...     },
...     scoring=weighted_acc,
... )

4.2. API-Schnittstelle#

Ein Konsument ist ein Objekt (Estimator, Meta-Estimator, Scorer, Splitter), das in mindestens einer seiner Methoden (z. B. fit, predict, inverse_transform, transform, score, split) einige Metadaten akzeptiert und verwendet. Meta-Estimators, die Metadaten nur an andere Objekte (Kind-Estimators, Scorer oder Splitter) weiterleiten und die Metadaten nicht selbst verwenden, sind keine Konsumenten. (Meta-)Estimators, die Metadaten an andere Objekte routen, sind Router. Ein (Meta-)Estimator kann gleichzeitig ein Konsument und ein Router sein. (Meta-)Estimators und Splitter stellen für jede Methode, die mindestens ein Metadatum akzeptiert, eine set_{method}_request-Methode bereit. Wenn ein Estimator beispielsweise sample_weight in fit und score unterstützt, stellt er estimator.set_fit_request(sample_weight=value) und estimator.set_score_request(sample_weight=value) bereit. Hier kann value sein:

  • True: Die Methode fordert sample_weight an. Das bedeutet, wenn die Metadaten bereitgestellt werden, werden sie verwendet, andernfalls wird kein Fehler ausgelöst.

  • False: Die Methode fordert sample_weight nicht an.

  • None: Der Router löst einen Fehler aus, wenn sample_weight übergeben wird. Dies ist in fast allen Fällen der Standardwert bei der Instanziierung eines Objekts und stellt sicher, dass der Benutzer die Metadatenanforderungen explizit festlegt, wenn Metadaten übergeben werden. Die einzige Ausnahme bilden Group*Fold-Splitter.

  • "param_name": Alias für sample_weight, wenn wir unterschiedliche Gewichtungen an verschiedene Konsumenten übergeben möchten. Wenn Aliase verwendet werden, sollte der Meta-Estimator "param_name" nicht an den Konsumenten weiterleiten, sondern sample_weight stattdessen, da der Konsument einen Parameter namens sample_weight erwartet. Das bedeutet, dass die Zuordnung zwischen den vom Objekt benötigten Metadaten, z. B. sample_weight, und dem vom Benutzer bereitgestellten Variablennamen, z. B. my_weights, auf Router-Ebene erfolgt und nicht vom konsumierenden Objekt selbst.

Metadaten werden für Scorer auf die gleiche Weise mit set_score_request angefordert.

Wenn Metadaten, z. B. sample_weight, vom Benutzer übergeben werden, sollte die Metadatenanforderung für alle Objekte, die sample_weight potenziell konsumieren können, vom Benutzer festgelegt werden, andernfalls wird ein Fehler vom Router-Objekt ausgelöst. Zum Beispiel löst der folgende Code einen Fehler aus, da nicht explizit angegeben wurde, ob sample_weight an den Scorer des Estimators übergeben werden soll oder nicht.

>>> param_grid = {"C": [0.1, 1]}
>>> lr = LogisticRegression().set_fit_request(sample_weight=True)
>>> try:
...     GridSearchCV(
...         estimator=lr, param_grid=param_grid
...     ).fit(X, y, sample_weight=my_weights)
... except ValueError as e:
...     print(e)
[sample_weight] are passed but are not explicitly set as requested or not
requested for LogisticRegression.score, which is used within GridSearchCV.fit.
Call `LogisticRegression.set_score_request({metadata}=True/False)` for each metadata
you want to request/ignore. See the Metadata Routing User guide
<https://scikit-learn.de/stable/metadata_routing.html> for more information.

Das Problem kann durch explizites Festlegen des Anforderungswerts behoben werden.

>>> lr = LogisticRegression().set_fit_request(
...     sample_weight=True
... ).set_score_request(sample_weight=False)

Am Ende des Abschnitts **Anwendungsbeispiele** deaktivieren wir das Konfigurationsflag für das Metadaten-Routing.

>>> sklearn.set_config(enable_metadata_routing=False)

4.3. Status der Metadaten-Routing-Unterstützung#

Alle Konsumenten (d. h. einfache Estimators, die nur Metadaten konsumieren und sie nicht weiterleiten) unterstützen Metadaten-Routing, was bedeutet, dass sie innerhalb von Meta-Estimators, die Metadaten-Routing unterstützen, verwendet werden können. Die Entwicklung der Unterstützung für Metadaten-Routing für Meta-Estimators ist jedoch im Gange, und hier ist eine Liste von Meta-Estimators und Tools, die Metadaten-Routing unterstützen und noch nicht unterstützen.

Meta-Estimators und Funktionen, die Metadaten-Routing unterstützen

Meta-Estimators und Tools, die Metadaten-Routing noch nicht unterstützen