web-dev-qa-db-fra.com

Utilisez GridSearchCV de sklearn avec un pipeline, prétraitement une seule fois

J'utilise scickit-learn pour régler un hyper-paramètres de modèle. J'utilise un pipeline pour enchaîner le prétraitement avec l'estimateur. Une version simple de mon problème ressemblerait à ceci:

import numpy as np
from sklearn.model_selection import GridSearchCV
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression


grid = GridSearchCV(make_pipeline(StandardScaler(), LogisticRegression()),
                    param_grid={'logisticregression__C': [0.1, 10.]},
                    cv=2,
                    refit=False)

_ = grid.fit(X=np.random.Rand(10, 3),
             y=np.random.randint(2, size=(10,)))

Dans mon cas, le prétraitement (ce qui serait StandardScale () dans l'exemple de jouet) prend du temps, et je ne règle aucun paramètre de celui-ci.

Ainsi, lorsque j'exécute l'exemple, le StandardScaler est exécuté 12 fois. 2 ajustement/prédiction * 2 cv * 3 paramètres. Mais chaque fois que StandardScaler est exécuté pour une valeur différente du paramètre C, il renvoie la même sortie, il serait donc beaucoup plus efficace de le calculer une fois, puis d'exécuter simplement la partie estimateur du pipeline.

Je peux séparer manuellement le pipeline entre le prétraitement (pas d'hyper paramètres réglés) et l'estimateur. Mais pour appliquer le prétraitement aux données, je dois fournir l'ensemble de formation uniquement. Donc, je devrais implémenter les divisions manuellement et ne pas utiliser GridSearchCV du tout.

Existe-t-il un moyen simple/standard d'éviter de répéter le prétraitement lors de l'utilisation de GridSearchCV?

19
Marc Garcia

Essentiellement, GridSearchCV est également un estimateur, implémentant des méthodes fit () et Predict (), utilisées par le pipeline.

Donc au lieu de:

grid = GridSearchCV(make_pipeline(StandardScaler(), LogisticRegression()),
                    param_grid={'logisticregression__C': [0.1, 10.]},
                    cv=2,
                    refit=False)

Faites ceci:

clf = make_pipeline(StandardScaler(), 
                    GridSearchCV(LogisticRegression(),
                                 param_grid={'logisticregression__C': [0.1, 10.]},
                                 cv=2,
                                 refit=True))

clf.fit()
clf.predict()

Ce qu'il fera, c'est d'appeler le StandardScalar () une seule fois, pour un appel à clf.fit() au lieu de plusieurs appels comme vous l'avez décrit.

Modifier:

Changement de refit en True, lorsque GridSearchCV est utilisé dans un pipeline. Comme mentionné dans la documentation :

refit: boolean, default = True Refit le meilleur estimateur avec l'ensemble de données complet. Si "False", il est impossible de faire des prédictions en utilisant cette instance de GridSearchCV après l'ajustement.

Si refit = False, clf.fit() n'aura aucun effet car l'objet GridSearchCV à l'intérieur du pipeline sera réinitialisé après fit(). Lorsque refit=True, Le GridSearchCV sera réaménagé avec la meilleure combinaison de paramètres de score sur l'ensemble des données transmises dans fit().

Donc, si vous voulez créer le pipeline, juste pour voir les scores de la recherche dans la grille, alors seulement refit=False Est approprié. Si vous souhaitez appeler la méthode clf.predict(), refit=True Doit être utilisé, sinon l'erreur Non ajusté sera levée.

25
Vivek Kumar

Il n'est pas possible de le faire dans la version actuelle de scikit-learn (0.18.1). Un correctif a été proposé sur le projet github:

https://github.com/scikit-learn/scikit-learn/issues/88

https://github.com/scikit-learn/scikit-learn/pull/8322

2
Victor Deplasse

Pour ceux qui sont tombés sur un problème un peu différent, que j'avais aussi.

Supposons que vous ayez ce pipeline:

classifier = Pipeline([
    ('vectorizer', CountVectorizer(max_features=100000, ngram_range=(1, 3))),
    ('clf', RandomForestClassifier(n_estimators=10, random_state=SEED, n_jobs=-1))])

Ensuite, lorsque vous spécifiez des paramètres, vous devez inclure ce nom 'clf _' que vous avez utilisé pour votre estimateur. Donc la grille des paramètres va être:

params={'clf__max_features':[0.3, 0.5, 0.7],
        'clf__min_samples_leaf':[1, 2, 3],
        'clf__max_depth':[None]
        }
0
Ayan Omarov