2016-06-25 17 views
13

Ho un set di dati con ~ 300 punti e 32 etichette distinte e voglio valutare un modello LinearSVR tracciando la sua curva di apprendimento utilizzando la ricerca della griglia e la convalida LabelKFold.Come nidificare LabelKFold?

Il codice che ho assomiglia a questo:

import numpy as np 
from sklearn import preprocessing 
from sklearn.svm import LinearSVR 
from sklearn.pipeline import Pipeline 
from sklearn.cross_validation import LabelKFold 
from sklearn.grid_search import GridSearchCV 
from sklearn.learning_curve import learning_curve 
    ... 
#get data (x, y, labels) 
    ... 
C_space = np.logspace(-3, 3, 10) 
epsilon_space = np.logspace(-3, 3, 10) 

svr_estimator = Pipeline([ 
    ("scale", preprocessing.StandardScaler()), 
    ("svr", LinearSVR), 
]) 

search_params = dict(
    svr__C = C_space, 
    svr__epsilon = epsilon_space 
) 

kfold = LabelKFold(labels, 5) 

svr_search = GridSearchCV(svr_estimator, param_grid = search_params, cv = ???) 

train_space = np.linspace(.5, 1, 10) 
train_sizes, train_scores, valid_scores = learning_curve(svr_search, x, y, train_sizes = train_space, cv = ???, n_jobs = 4) 
    ... 
#plot learning curve 

La mia domanda è come impostare l'attributo di cv per la ricerca della rete e la curva di apprendimento in modo che possa rompere il mio originale set in set di formazione e di test che don condividere le etichette per calcolare la curva di apprendimento. E poi da questi set di allenamento, li separa ulteriormente in training e set di test senza condividere etichette per la ricerca della griglia?

In sostanza, come si esegue un LabelKFold nidificato?


io, l'utente che ha creato la bontà per questa domanda, ha scritto il seguente esempio riproducibili utilizzando dati disponibili da sklearn.

import numpy as np 
from sklearn.datasets import load_digits 
from sklearn.ensemble import RandomForestClassifier 
from sklearn.metrics import make_scorer, roc_auc_score 
from sklearn.grid_search import GridSearchCV 
from sklearn.cross_validation import cross_val_score, LabelKFold 

digits = load_digits() 
X = digits['data'] 
Y = digits['target'] 
Z = np.zeros_like(Y) ## this is just to make a 2-class problem, purely for the sake of an example 
Z[np.where(Y>4)]=1 

strata = [x % 13 for x in xrange(Y.size)] # define the strata for use in 

## define stuff for nested cv... 
mtry = [5, 10] 
tuned_par = {'max_features': mtry} 
toy_rf = RandomForestClassifier(n_estimators=10, max_depth=10, random_state=10, 
           class_weight="balanced") 
roc_auc_scorer = make_scorer(roc_auc_score, needs_threshold=True) 

## define outer k-fold label-aware cv 
outer_cv = LabelKFold(labels=strata, n_folds=5) 

############################################################################# 
## this works: using regular randomly-allocated 10-fold CV in the inner folds 
############################################################################# 
vanilla_clf = GridSearchCV(estimator=toy_rf, param_grid=tuned_par, scoring=roc_auc_scorer, 
         cv=5, n_jobs=1) 
vanilla_results = cross_val_score(vanilla_clf, X=X, y=Z, cv=outer_cv, n_jobs=1) 

########################################################################## 
## this does not work: attempting to use label-aware CV in the inner loop 
########################################################################## 
inner_cv = LabelKFold(labels=strata, n_folds=5) 
nested_kfold_clf = GridSearchCV(estimator=toy_rf, param_grid=tuned_par, scoring=roc_auc_scorer, 
           cv=inner_cv, n_jobs=1) 
nested_kfold_results = cross_val_score(nested_kfold_clf, X=X, y=Y, cv=outer_cv, n_jobs=1) 

risposta

3

Dalla tua domanda, che desideri per il punteggio LabelKFold sui vostri dati, mentre la griglia ricerca i parametri della vostra pipeline in ciascuna delle iterazioni di questa LabelKFold esterno, utilizzando ancora una volta un LabelKFold. Anche se non è stato in grado di raggiungere questo out-of-the-box ci vuole solo un ciclo:

outer_cv = LabelKFold(labels=strata, n_folds=3) 
strata = np.array(strata) 
scores = [] 
for outer_train, outer_test in outer_cv: 
    print "Outer set. Train:", set(strata[outer_train]), "\tTest:", set(strata[outer_test]) 
    inner_cv = LabelKFold(labels=strata[outer_train], n_folds=3) 
    print "\tInner:" 
    for inner_train, inner_test in inner_cv: 
     print "\t\tTrain:", set(strata[outer_train][inner_train]), "\tTest:", set(strata[outer_train][inner_test]) 
    clf = GridSearchCV(estimator=toy_rf, param_grid=tuned_par, scoring=roc_auc_scorer, cv= inner_cv, n_jobs=1) 
    clf.fit(X[outer_train],Z[outer_train]) 
    scores.append(clf.score(X[outer_test], Z[outer_test])) 

esecuzione del codice, i primi rese iterazione:

Outer set. Train: set([0, 1, 4, 5, 7, 8, 10, 11]) Test: set([9, 2, 3, 12, 6]) 
Inner: 
    Train: set([0, 10, 11, 5, 7]) Test: set([8, 1, 4]) 
    Train: set([1, 4, 5, 8, 10, 11]) Test: set([0, 7]) 
    Train: set([0, 1, 4, 8, 7])  Test: set([10, 11, 5]) 

Quindi, è facile verificare che venga eseguito come previsto. I tuoi punteggi di convalida incrociata sono nella lista scores e puoi elaborarli facilmente. Ho utilizzato le variabili, ad esempio strata definite nell'ultima porzione di codice.

+0

Questo è praticamente il modo in cui ho dovuto farlo, facendo il ciclo kfold da solo ed eseguendo la ricerca della griglia su singole pieghe. Sono l'interrogante originale, ma non sono quello che ha messo una taglia su questa domanda. Non sono sicuro di come funzioni, ma ho intenzione di revocare questa risposta perché è la soluzione migliore che io conosca. Tuttavia, aspetterò la risposta del titolare della taglia prima di accettare la risposta. – Alex

+0

Questo sembra molto fattibile - darò un vortice a questo. Sembrerebbe che questo sia il modo giusto per farlo. Grazie mille. FWIW, @Alex, credo che solo io possa assegnare la taglia, quindi geompalik può aspettarselo nelle prossime 24 ore. – Sycorax