Evalml: BalancedClassificationDataCVSplitは、呼び出されるたびに異なる分割を生成します

作成日 2021年03月16日  ·  3コメント  ·  ソース: alteryx/evalml

再現

import joblib
from evalml.demos import load_fraud
from evalml.preprocessing.data_splitters import BalancedClassificationDataCVSplit

splitter = BalancedClassificationDataCVSplit(n_splits=3, random_seed=0, shuffle=True)

X, y = load_fraud(5000)
X = X.to_dataframe()
y = y.to_series().astype("int")

for train, test in splitter.split(X, y):
    print((joblib.hash(train), joblib.hash(test)))

# Output
('75f1b95d7ce307ac6c793055330969aa', '8c89fe1a592c50a700b6d5cbb02dba8b')
('f8c849bbfbed37c13f66c5c742e237cb', '9c4879fb550fded8be9ac03e95a1bf95')
('cdc21f0d6bbf45459c9695258f7f04dc', '5b575765bbe176e732b8eb4dc1bf2822')

for train, test in splitter.split(X, y):
    print((joblib.hash(train), joblib.hash(test)))

# Output
('bf462b82af243c552ac48acad2dfd748', '8c89fe1a592c50a700b6d5cbb02dba8b')
('b8341b536c63c7957c099b05e315f49c', '9c4879fb550fded8be9ac03e95a1bf95')
('780e74673b601790037fc0b17dde56fe', '5b575765bbe176e732b8eb4dc1bf2822')

for train, test in splitter.split(X, y):
    print((joblib.hash(train), joblib.hash(test)

# Output
('385f6c538568ad3a33cf84f61d94144c', '8c89fe1a592c50a700b6d5cbb02dba8b')
('8db65d0a3bdf87ae0f135b9766a260dd', '9c4879fb550fded8be9ac03e95a1bf95')
('2a7293fc1308b8a572091d7c76d20205', '5b575765bbe176e732b8eb4dc1bf2822')

これは、sklearnスプリッターの動作とは異なります。

from sklearn.model_selection import StratifiedKFold

kfold = StratifiedKFold(n_splits=3, random_state=0, shuffle=True)

for train, test in kfold.split(X, y):
    print((joblib.hash(train), joblib.hash(test)))

#Output
('6c30ee6a11803927024354405389506a', '8c89fe1a592c50a700b6d5cbb02dba8b')
('df0a70e2e6ca783f12461e8c82a26ad4', '9c4879fb550fded8be9ac03e95a1bf95')
('2898e4b3d3621b436641016499f4aafb', '5b575765bbe176e732b8eb4dc1bf2822')

for train, test in kfold.split(X, y):
    print((joblib.hash(train), joblib.hash(test)))

# Output
('6c30ee6a11803927024354405389506a', '8c89fe1a592c50a700b6d5cbb02dba8b')
('df0a70e2e6ca783f12461e8c82a26ad4', '9c4879fb550fded8be9ac03e95a1bf95')
('2898e4b3d3621b436641016499f4aafb', '5b575765bbe176e732b8eb4dc1bf2822')

これには2つの理由で問題があると思います。

  1. BalancedClassificationDataCVSplitはautomlのデフォルトのスプリッターであるため、パイプラインがさまざまな分割で評価されることを意味します
  2. splitはデータスプリッターの状態を変更するため、シーケンシャルエンジンとパラレルエンジンの間で異なる結果が得られることを意味します。
bug

全てのコメント3件

これを指摘してくれてありがとう。

個人的には、この振る舞いは私を悩ませません。 特定のシードで初期化するたびに、その時点以降に同じ出力シーケンスが得られる限り、問題はありません。 ランダムシードを尊重していなかったら心配です。 しかし、それはこの問題が追跡するものではありません。

私の推奨事項:何もしないでください。 そのため、終了します。

@freddyaboultonこの振る舞いについて同意できない場合は、それを

@dsherryこれは2つの理由で変更する価値があると思います。

  1. さまざまなパイプラインがさまざまなデータで評価されるため、automl検索に差異が生じます。 これにより、スコアが同じデータで計算されないため、ランキングテーブルが少し誤解を招く可能性があります。
  2. 並列自動検索には適していません

    2について詳しく説明します。現在の動作では、シーケンシャルエンジンは、検索全体を通じてデータスプリッターの状態を変更することが期待されています。 並列evalmlでは、データスプリッターをピクルスし、それをワーカーに送信して分割を計算します。 ワーカーはスプリッターのコピーを取得するため、元のデータスプリッターの状態を変更しません。

これにより、パイプラインが評価される順序によっては分割が一致しないため、シーケンシャルエンジンとパラレルエンジンの動作に違いが生じます。 これは、同じパイプライン/パラメーターの組み合わせがシーケンシャルエンジンとパラレルエンジンで異なる結果をもたらすことを意味し、それは望ましくないと思います。

私の意見では、意味のある比較ができるようにするには、すべてのパイプラインを同じデータで評価する必要があるため、ポイント1はこれを修正するのに十分な理由です。 しかし、並列evalmlに移行するときは、グローバル状態の変更が期待される動作の一部ではないことを確認することが重要だと思います。

今後の計画:

  1. BalancedClassificationDataCVSplit変更して、この問題を修正してください
  2. 長期的には、automl検索で異なるパイプラインに異なる分割をフィードしないことを確認するテストを作成したいと思います。

みなさん、ありがとうございました!

このページは役に立ちましたか?
0 / 5 - 0 評価