1. 元數據路由#
注意
元數據路由 API 仍在實驗階段,尚未在所有估計器中實作。請參考支援和不支援的模型列表以取得更多資訊。它可能會在沒有通常的棄用週期下變更。預設情況下,此功能未啟用。您可以將 enable_metadata_routing
標誌設定為 True
來啟用它
>>> import sklearn
>>> sklearn.set_config(enable_metadata_routing=True)
請注意,本文件中介紹的方法和要求僅在您想將元數據(例如 sample_weight
)傳遞給方法時才相關。如果您只傳遞 X
和 y
,並且沒有將其他參數/元數據傳遞給諸如 fit、transform 等方法,那麼您無需設定任何內容。
本指南示範了如何在 scikit-learn 中的物件之間路由和傳遞元數據。如果您正在開發與 scikit-learn 相容的估計器或元估計器,您可以查看我們相關的開發人員指南:元數據路由。
元數據是估計器、評分器或 CV 分割器在使用者明確將其作為參數傳遞時會考慮的數據。例如,KMeans
接受其 fit()
方法中的 sample_weight
,並將其用於計算其質心。classes
由某些分類器使用,而 groups
在某些分割器中使用,但除了 X 和 y 之外,傳遞到物件方法中的任何數據都可以視為元數據。在 scikit-learn 1.3 版之前,如果這些物件與其他物件一起使用,例如在 GridSearchCV
中接受 sample_weight
的評分器,則沒有單一 API 可以傳遞類似的元數據。
使用元數據路由 API,我們可以通過元估計器(例如 Pipeline
或 GridSearchCV
)或諸如 cross_validate
之類的函數,將元數據傳輸到估計器、評分器和 CV 分割器,這些函數會將數據路由到其他物件。為了將元數據傳遞給諸如 fit
或 score
之類的方法,使用元數據的物件必須請求它。這是通過 set_{method}_request()
方法完成的,其中 {method}
由請求元數據的方法名稱取代。例如,在其 fit()
方法中使用元數據的估計器將使用 set_fit_request()
,而評分器將使用 set_score_request()
。這些方法允許我們指定要請求的元數據,例如 set_fit_request(sample_weight=True)
。
對於諸如 GroupKFold
之類的分組分割器,預設會請求 groups
參數。這最好通過以下範例來說明。
1.1. 使用範例#
在這裡,我們提供一些範例來展示一些常見的使用案例。我們的目標是通過 cross_validate
傳遞 sample_weight
和 groups
,該函數將元數據路由到 LogisticRegressionCV
和使用 make_scorer
製作的自訂評分器,兩者都可以在其方法中使用元數據。在這些範例中,我們希望個別設定是否在不同的使用者中使用元數據。
本節中的範例需要以下匯入和數據
>>> 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)
1.1.1. 加權評分和擬合#
LogisticRegressionCV
內部使用的分割器 GroupKFold
預設會請求 groups
。但是,我們需要通過在 LogisticRegressionCV`的 `set_fit_request()
方法和 make_scorer`的 `set_score_request
方法中指定 sample_weight=True
來明確請求它和我們的自訂評分器。兩個使用者都知道如何在他們的 fit()
或 score()
方法中使用 sample_weight
。然後,我們可以在 cross_validate
中傳遞元數據,它會將其路由到任何活動的使用者
>>> weighted_acc = make_scorer(accuracy_score).set_score_request(sample_weight=True)
>>> lr = LogisticRegressionCV(
... cv=GroupKFold(),
... scoring=weighted_acc
... ).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,
... )
請注意,在本範例中,cross_validate
將 my_weights
路由到評分器和 LogisticRegressionCV
。
如果我們在 cross_validate
的參數中傳遞 sample_weight
,但沒有設定任何物件來請求它,則會引發 UnsetMetadataPassedError
,提示我們需要明確設定將其路由到何處。如果傳遞了 params={"sample_weights": my_weights, ...}
(請注意拼寫錯誤,即 weights
而不是 weight
),情況也是如此,因為沒有任何底層物件請求 sample_weights
。
1.1.2. 加權評分與非加權擬合#
當將諸如 sample_weight
之類的元數據傳遞到 路由器(元估計器 或路由函式)時,所有 sample_weight
消費者 都需要明確請求權重或明確不請求權重(即 True
或 False
)。因此,要執行非加權擬合,我們需要將 LogisticRegressionCV
設定為不請求樣本權重,以便 cross_validate
不會傳遞權重。
>>> weighted_acc = make_scorer(accuracy_score).set_score_request(sample_weight=True)
>>> lr = LogisticRegressionCV(
... cv=GroupKFold(), scoring=weighted_acc,
... ).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,
... )
如果沒有呼叫 linear_model.LogisticRegressionCV.set_fit_request
,cross_validate
將會引發錯誤,因為傳遞了 sample_weight
,但 LogisticRegressionCV
並未明確配置為識別權重。
1.1.3. 非加權特徵選擇#
只有當物件的方法知道如何使用元數據時,才能路由元數據,這在大多數情況下表示它們將元數據作為明確的參數。只有這樣,我們才能使用 set_fit_request(sample_weight=True)
等設定元數據的請求值。這會使物件成為 消費者。
與 LogisticRegressionCV
不同,SelectKBest
無法消耗權重,因此其執行個體上沒有設定 sample_weight
的請求值,並且 sample_weight
不會路由到它。
>>> weighted_acc = make_scorer(accuracy_score).set_score_request(sample_weight=True)
>>> lr = LogisticRegressionCV(
... cv=GroupKFold(), scoring=weighted_acc,
... ).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,
... )
1.1.4. 不同的評分和擬合權重#
儘管 make_scorer
和 LogisticRegressionCV
都期望使用鍵 sample_weight
,但我們可以使用別名將不同的權重傳遞給不同的消費者。在此範例中,我們將 scoring_weight
傳遞給評分器,並將 fitting_weight
傳遞給 LogisticRegressionCV
。
>>> weighted_acc = make_scorer(accuracy_score).set_score_request(
... sample_weight="scoring_weight"
... )
>>> lr = LogisticRegressionCV(
... cv=GroupKFold(), scoring=weighted_acc,
... ).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,
... )
1.2. API 介面#
消費者 是一個物件(估計器、元估計器、評分器、分割器),它在其至少一個方法中接受並使用一些 元數據(例如 fit
、predict
、inverse_transform
、transform
、score
、split
)。僅將元數據轉發到其他物件(子估計器、評分器或分割器)而不使用元數據本身的元估計器不是消費者。將元數據路由到其他物件的(元)估計器是 路由器。(元)估計器可以同時是 消費者 和 路由器。(元)估計器和分割器會為每個至少接受一個元數據的方法公開一個 set_{method}_request
方法。例如,如果估計器在 fit
和 score
中支援 sample_weight
,則它會公開 estimator.set_fit_request(sample_weight=value)
和 estimator.set_score_request(sample_weight=value)
。這裡 value
可以是
True
:方法請求sample_weight
。這表示如果提供了元數據,將會使用它,否則不會引發錯誤。False
:方法不請求sample_weight
。None
:如果傳遞了sample_weight
,路由器將會引發錯誤。在大多數情況下,這是物件實例化時的預設值,並確保使用者在傳遞元數據時明確設定元數據請求。唯一的例外是Group*Fold
分割器。"param_name"
:如果我們想將不同的權重傳遞給不同的消費者,則為sample_weight
的別名。如果使用了別名,則元估計器不應將"param_name"
轉發給消費者,而應轉發sample_weight
,因為消費者會預期有一個名為sample_weight
的參數。這表示物件要求的元數據(例如sample_weight
)與使用者提供的變數名稱(例如my_weights
)之間的映射是在路由器層級完成的,而不是由消耗物件本身完成的。
使用 set_score_request
以相同的方式請求評分器的元數據。
如果使用者傳遞了元數據(例如 sample_weight
),則應由使用者設定所有可能消耗 sample_weight
的物件的元數據請求,否則路由器物件會引發錯誤。例如,以下程式碼會引發錯誤,因為尚未明確指定是否應將 sample_weight
傳遞給估計器的評分器。
>>> 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.
可以透過明確設定請求值來修正此問題。
>>> lr = LogisticRegression().set_fit_request(
... sample_weight=True
... ).set_score_request(sample_weight=False)
在 **用法範例** 章節的末尾,我們會停用元數據路由的組態旗標。
>>> sklearn.set_config(enable_metadata_routing=False)
1.3. 元數據路由支援狀態#
所有消費者(即僅消耗元數據而不路由它們的簡單估計器)都支援元數據路由,這表示它們可以在支援元數據路由的元估計器中使用。然而,正在進行對元估計器支援元數據路由的開發,以下是支援和尚不支援元數據路由的元估計器和工具的清單。
支援元數據路由的元估計器和函式
不支援元數據路由的中繼估算器與工具