Evalml: BalancedClassificationDataCVSplit produit des divisions différentes à chaque appel

Créé le 16 mars 2021  ·  3Commentaires  ·  Source: alteryx/evalml

Repro

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')

Ceci est différent du comportement du séparateur 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')

Je pense que cela pose problème pour deux raisons :

  1. Étant donné que BalancedClassificationDataCVSplit est le séparateur par défaut dans automl, cela signifie que nos pipelines sont évalués sur différents partages
  2. Étant donné que split modifie l'état du séparateur de données, cela signifie que nous aurons des résultats différents entre les moteurs séquentiels et parallèles.
bug

Tous les 3 commentaires

Merci de l'avoir signalé.

Personnellement, ce comportement ne me dérange pas. Tant que chaque fois que nous initialisons avec une certaine graine, nous obtenons la même séquence de sortie après ce point, tout va bien. Je serais inquiet si nous ne respections pas la graine aléatoire; mais ce n'est pas ce que ce problème suit.

Ma recommandation : ne rien faire. En tant que tel, fermeture.

@freddyaboulton si vous n'êtes pas d'accord sur ce comportement, affrontons-le, je veux dire parler

@dsherry Je pense que cela vaut la peine de changer pour deux raisons :

  1. Il introduit des variations dans la recherche automatique car différents pipelines sont évalués sur différentes données. Cela rend le tableau de classement légèrement trompeur car les scores ne sont pas calculés sur les mêmes données.
  2. C'est mauvais pour la recherche automatique en parallèle

    Permettez-moi d'élaborer sur 2. Avec le comportement actuel, le moteur séquentiel devrait modifier l'état du séparateur de données tout au long de la recherche. En parallèle evalml, nous sélectionnons le séparateur de données et l'envoyons aux travailleurs pour calculer le partage. Étant donné que les travailleurs obtiennent une copie du séparateur, ils ne modifient pas l'état du séparateur de données d'origine.

Cela introduit une différence de comportement entre les moteurs séquentiels et parallèles car les divisions ne correspondraient pas en fonction de l'ordre dans lequel le pipeline est évalué ! Cela signifie que le même combo pipeline/paramètre obtiendrait des résultats différents dans le moteur séquentiel et le moteur parallèle et je pense que ce n'est pas souhaitable.

À mon avis, le point 1 est une raison suffisante pour résoudre ce problème car tous nos pipelines devraient être évalués sur les mêmes données si nous voulons pouvoir les comparer de manière significative. Mais alors que nous nous dirigeons vers l'evalml parallèle, je pense qu'il est important de nous assurer que la modification de l'état global ne fait pas partie de notre comportement attendu.

Le plan pour l'avenir :

  1. Corrigez ce problème en modifiant le BalancedClassificationDataCVSplit
  2. À plus long terme, nous aimerions écrire des tests qui vérifient que nous n'alimentons pas différents fractionnements dans différents pipelines dans la recherche automatique.

Merci pour la discussion à tous !

Cette page vous a été utile?
0 / 5 - 0 notes