0

J'aime utiliser le LOGO de scikit (laisser un groupe) comme méthode de validation croisée, en combinaison avec des courbes d'apprentissage. Cela fonctionne très bien dans la plupart des cas que je traite, mais je ne peux (efficacement) utiliser que les deux paramètres qui sont (je crois) les plus critiques dans ces cas (d'expérience): caractéristiques maximales et nombre d'estimateurs. Exemple de mon code ci-dessous:Combinaison de RandomizedSearchCV (ou GridSearcCV) avec la validation croisée LeaveOneGroupOut dans scikit-learn

Fscorer = make_scorer(f1_score, average = 'micro') 
    gp = training_data["GP"].values 
    logo = LeaveOneGroupOut() 
    from sklearn.ensemble import RandomForestClassifier 
    RF_clf100 = RandomForestClassifier (n_estimators=100, n_jobs=-1, random_state = 49) 
    RF_clf200 = RandomForestClassifier (n_estimators=200, n_jobs=-1, random_state = 49) 
    RF_clf300 = RandomForestClassifier (n_estimators=300, n_jobs=-1, random_state = 49) 
    RF_clf400 = RandomForestClassifier (n_estimators=400, n_jobs=-1, random_state = 49) 
    RF_clf500 = RandomForestClassifier (n_estimators=500, n_jobs=-1, random_state = 49) 
    RF_clf600 = RandomForestClassifier (n_estimators=600, n_jobs=-1, random_state = 49) 

    param_name = "max_features" 
    param_range = param_range = [5, 10, 15, 20, 25, 30] 


    plt.figure() 
    plt.suptitle('n_estimators = 100', fontsize=14, fontweight='bold') 
    _, test_scores = validation_curve(RF_clf100, X, y, cv=logo.split(X, y, groups=gp), 
             param_name=param_name, param_range=param_range, 
             scoring=Fscorer, n_jobs=-1) 
    test_scores_mean = np.mean(test_scores, axis=1) 
    plt.plot(param_range, test_scores_mean) 
    plt.xlabel(param_name) 
    plt.xlim(min(param_range), max(param_range)) 
    plt.ylabel("F1") 
    plt.ylim(0.47, 0.57) 
    plt.legend(loc="best") 
    plt.show() 


    plt.figure() 
    plt.suptitle('n_estimators = 200', fontsize=14, fontweight='bold') 
    _, test_scores = validation_curve(RF_clf200, X, y, cv=logo.split(X, y, groups=gp), 
             param_name=param_name, param_range=param_range, 
             scoring=Fscorer, n_jobs=-1) 
    test_scores_mean = np.mean(test_scores, axis=1) 
    plt.plot(param_range, test_scores_mean) 
    plt.xlabel(param_name) 
    plt.xlim(min(param_range), max(param_range)) 
    plt.ylabel("F1") 
    plt.ylim(0.47, 0.57) 
    plt.legend(loc="best") 
    plt.show() 
    ... 
    ... 

Ce que je voudrais vraiment bien est de combiner le logo avec la recherche de la grille ou la recherche aléatoire, pour une recherche d'espace des paramètres plus approfondie.

A partir de maintenant mon code ressemble à ceci:

param_dist = {"n_estimators": [100, 200, 300, 400, 500, 600], 
       "max_features": sp_randint(5, 30), 
       "max_depth": sp_randint(2, 18), 
       "criterion": ['entropy', 'gini'], 
       "min_samples_leaf": sp_randint(2, 17)} 

clf = RandomForestClassifier(random_state = 49) 

n_iter_search = 45 
random_search = RandomizedSearchCV(clf, param_distributions=param_dist, 
            n_iter=n_iter_search, 
            scoring=Fscorer, cv=8, 
            n_jobs=-1) 
random_search.fit(X, y) 

Quand je remplace cv = 8 avec cv=logo.split(X, y, groups=gp), je reçois ce message d'erreur:

--------------------------------------------------------------------------- 
TypeError         Traceback (most recent call last) 
<ipython-input-10-0092e11ffbf4> in <module>() 
---> 35 random_search.fit(X, y) 


/Applications/anaconda/lib/python2.7/site-packages/sklearn/model_selection/_search.pyc in fit(self, X, y, groups) 
    1183           self.n_iter, 
    1184           random_state=self.random_state) 
-> 1185   return self._fit(X, y, groups, sampled_params) 

/Applications/anaconda/lib/python2.7/site-packages/sklearn/model_selection/_search.pyc in _fit(self, X, y, groups, parameter_iterable) 
    540 
    541   X, y, groups = indexable(X, y, groups) 
--> 542   n_splits = cv.get_n_splits(X, y, groups) 
    543   if self.verbose > 0 and isinstance(parameter_iterable, Sized): 
    544    n_candidates = len(parameter_iterable) 

/Applications/anaconda/lib/python2.7/site-packages/sklearn/model_selection/_split.pyc in get_n_splits(self, X, y, groups) 
    1489    Returns the number of splitting iterations in the cross-validator. 
    1490   """ 
-> 1491   return len(self.cv) # Both iterables and old-cv objects support len 
    1492 
    1493  def split(self, X=None, y=None, groups=None): 

TypeError: object of type 'generator' has no len() 

Toutes les suggestions à (1) ce qui se passe et, plus important encore, (2) comment je peux le faire fonctionner (combinant RandomizedSearchCV avec LeaveOneGroupOut)?

* Mise à jour février 08 2017 *

Il a travaillé à l'aide cv=logo avec suggestion « @Vivek Kumar de random_search.fit(X, y, wells)

Répondre

1

Vous ne devriez pas passer logo.split() dans le RandomizedSearchCV, passer seulement un objet cv comme en logo il. Le RandomizedSearchCV appelle en interne split() pour générer des indices de test de train. Vous pouvez transmettre vos groupes gp dans l'appel fit() à l'objet RandomizedSearchCV ou GridSearchCV.

au lieu de le faire:

random_search.fit(X, y) 

Faites ceci:

random_search.fit(X, y, gp) 

EDIT: vous pouvez également passer gp au constructeur de GridSearchCV ou RandomizedSearchCV dans le paramètre fit_params comme dict.

+0

Je ne suis pas sûr de comprendre. Où dois-je passer 'cv.get_n_splits'? – MyCarta

+0

@MyCarta Désolé, je parlais de 'logo.split()', pas 'cv.get_n_splits'. J'ai édité ma réponse pour enlever la confusion. –

+0

@ Vivek Kumar ok c'est un peu plus clair. Êtes-vous également en train de dire qu'il n'y a pas de solution de contournement? – MyCarta