Evalml: BalancedClassificationDataCVSplit erzeugt bei jedem Aufruf unterschiedliche Splits

Erstellt am 16. März 2021  ·  3Kommentare  ·  Quelle: 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')

Dies unterscheidet sich vom Verhalten des Sklearn-Splitters:

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

Das halte ich aus zwei Gründen für problematisch:

  1. Da BalancedClassificationDataCVSplit der Standard-Splitter in Automl ist, bedeutet dies, dass unsere Pipelines auf verschiedenen Splits ausgewertet werden
  2. Da split den Zustand des Datensplitters ändert, bedeutet dies, dass wir unterschiedliche Ergebnisse zwischen den sequentiellen und parallelen Engines haben.
bug

Alle 3 Kommentare

Danke für den Hinweis.

Mich persönlich stört dieses Verhalten nicht. Solange wir jedes Mal, wenn wir mit einem bestimmten Seed initialisieren, nach diesem Punkt die gleiche Ausgabesequenz erhalten, sind wir gut. Ich würde mir Sorgen machen, wenn wir die zufällige Saat nicht respektieren würden; aber das ist nicht das, was dieses Problem verfolgt.

Meine Empfehlung: Nichts tun. Als solche schließen.

@freddyaboulton wenn du mit diesem Verhalten nicht einverstanden bist, lass es uns ausreden, ich meine reden

@dsherry Ich denke, es lohnt sich aus zwei Gründen, dies zu ändern:

  1. Es führt Abweichungen in die Automl-Suche ein, da verschiedene Pipelines für verschiedene Daten ausgewertet werden. Dies führt dazu, dass die Ranglistentabelle leicht irreführend ist, da die Bewertungen nicht auf den gleichen Daten berechnet werden.
  2. Es ist schlecht für die parallele Automl-Suche

    Lassen Sie mich auf 2 eingehen. Beim aktuellen Verhalten wird erwartet, dass die sequentielle Engine den Zustand des Datensplitters während der Suche ändert. In der parallelen evalml picken wir den Datensplitter und senden ihn an die Arbeiter, um die Aufteilung zu berechnen. Da die Arbeiter eine Kopie des Splitters erhalten, ändern sie den Zustand des ursprünglichen Datensplitters nicht.

Dies führt zu einem Unterschied im Verhalten zwischen den sequentiellen und parallelen Engines, da die Aufteilungen abhängig von der Reihenfolge, in der die Pipeline ausgewertet wird, nicht übereinstimmen würden! Dies bedeutet, dass dieselbe Pipeline/Parameter-Kombination in der sequentiellen Engine und der parallelen Engine unterschiedliche Ergebnisse erzielen würde, und ich denke, das ist unerwünscht.

Punkt 1 ist meiner Meinung nach Grund genug, dies zu beheben, denn alle unsere Pipelines sollten mit den gleichen Daten bewertet werden, wenn wir sie sinnvoll vergleichen wollen. Aber wenn wir uns auf parallele evalml zubewegen, denke ich, dass es wichtig ist, dass wir sicherstellen, dass das Ändern des globalen Zustands nicht Teil unseres erwarteten Verhaltens ist.

Der Plan geht weiter:

  1. Beheben Sie dieses Problem, indem Sie BalancedClassificationDataCVSplit
  2. Längerfristig möchten wir Tests schreiben, die überprüfen, ob wir in der Automl-Suche verschiedene Splits an verschiedene Pipelines füttern.

Danke für die Diskussion an alle!

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen