Evalml: BalancedClassificationDataCVSplit produz divisões diferentes cada vez que é chamado

Criado em 16 mar. 2021  ·  3Comentários  ·  Fonte: 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')

Isso é diferente do comportamento do divisor 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')

Acho que isso é problemático por dois motivos:

  1. Como BalancedClassificationDataCVSplit é o divisor padrão em automl, isso significa que nossos pipelines são avaliados em diferentes divisões
  2. Como split modifica o estado do divisor de dados, isso significa que teremos resultados diferentes entre os mecanismos sequencial e paralelo.
bug

Todos 3 comentários

Obrigado por apontar isso.

Pessoalmente, esse comportamento não me incomoda. Contanto que toda vez que inicializarmos com uma determinada semente, obtivermos a mesma sequência de saída após esse ponto, estamos bem. Eu ficaria preocupado se não estivéssemos respeitando a semente aleatória; mas não é isso que esse problema rastreia.

Minha recomendação: não faça nada. Como tal, fechando.

@freddyaboulton se você discordar desse comportamento, vamos brigar, quero dizer, conversar 😅

@dsherry Acho que vale a pena mudar por dois motivos:

  1. Ele apresenta variações à pesquisa automática porque diferentes pipelines são avaliados em dados diferentes. Isso torna a tabela de classificação um pouco enganosa, porque as pontuações não são calculadas com base nos mesmos dados.
  2. É ruim para pesquisa automática paralela

    Deixe-me explicar melhor 2. Com o comportamento atual, espera-se que o mecanismo sequencial modifique o estado do divisor de dados durante a pesquisa. Em evalml paralelo, selecionamos o divisor de dados e o enviamos aos trabalhadores para calcular a divisão. Como os trabalhadores obtêm uma cópia do divisor, eles não modificam o estado do divisor de dados original.

Isso introduz uma diferença de comportamento entre os mecanismos sequenciais e paralelos porque as divisões não corresponderiam, dependendo da ordem em que o pipeline é avaliado! Isso significa que a mesma combinação de pipeline / parâmetro obteria resultados diferentes no mecanismo sequencial e no mecanismo paralelo, e acho isso indesejável.

Na minha opinião, o ponto 1 é motivo suficiente para corrigir isso, porque todos os nossos pipelines devem ser avaliados nos mesmos dados se quisermos poder compará-los de forma significativa. Mas, à medida que avançamos em direção à avaliação paralela, acho importante nos certificarmos de que modificar o estado global não faz parte do nosso comportamento esperado.

O plano para seguir em frente:

  1. Corrija este problema modificando o BalancedClassificationDataCVSplit
  2. A longo prazo, gostaríamos de escrever testes que verifiquem que não alimentamos diferentes divisões para diferentes pipelines na pesquisa automática.

Obrigado a todos pela discussão!

Esta página foi útil?
0 / 5 - 0 avaliações