2016-04-17 11 views
6

Sto tentando di concatenare la ricerca di rete e l'eliminazione di feature ricorsive in una pipeline utilizzando scikit-learn.Ricerca griglia con funzionalità ricorsiva L'eliminazione nella pipeline di scikit-learn restituisce un errore

GridSearchCV e RFE con classificatore "nuda" funziona bene:

from sklearn.datasets import make_friedman1 
from sklearn import feature_selection 
from sklearn.grid_search import GridSearchCV 
from sklearn.svm import SVR 

X, y = make_friedman1(n_samples=50, n_features=10, random_state=0) 

est = SVR(kernel="linear") 

selector = feature_selection.RFE(est) 
param_grid = dict(estimator__C=[0.1, 1, 10]) 
clf = GridSearchCV(selector, param_grid=param_grid, cv=10) 
clf.fit(X, y) 

Mettere classificatore in una pipeline restituisce un errore: RuntimeError: Il classificatore non espone "coef_" o "feature_importances_" attributi

from sklearn.datasets import make_friedman1 
from sklearn import feature_selection 
from sklearn import preprocessing 
from sklearn import pipeline 
from sklearn.grid_search import GridSearchCV 
from sklearn.svm import SVR 

X, y = make_friedman1(n_samples=50, n_features=10, random_state=0) 

est = SVR(kernel="linear") 

std_scaler = preprocessing.StandardScaler() 
pipe_params = [('std_scaler', std_scaler), ('clf', est)] 
pipe = pipeline.Pipeline(pipe_params) 

selector = feature_selection.RFE(pipe) 
param_grid = dict(estimator__clf__C=[0.1, 1, 10]) 
clf = GridSearchCV(selector, param_grid=param_grid, cv=10) 
clf.fit(X, y) 

EDIT:

ho capito che non mi era chiaro che descrive il problema. Questo è il frammento di più chiaro:

from sklearn.datasets import make_friedman1 
from sklearn import feature_selection 
from sklearn import pipeline 
from sklearn.grid_search import GridSearchCV 
from sklearn.svm import SVR 

X, y = make_friedman1(n_samples=50, n_features=10, random_state=0) 

# This will work 
est = SVR(kernel="linear") 
selector = feature_selection.RFE(est) 
clf = GridSearchCV(selector, param_grid={'estimator__C': [1, 10]}) 
clf.fit(X, y) 

# This will not work 
est = pipeline.make_pipeline(SVR(kernel="linear")) 
selector = feature_selection.RFE(est) 
clf = GridSearchCV(selector, param_grid={'estimator__svr__C': [1, 10]}) 
clf.fit(X, y) 

Come si può vedere, l'unica differenza sta mettendo lo stimatore in una pipeline. La pipeline, tuttavia, nasconde gli attributi "coef_" o "feature_importances_". Le domande sono:

  1. C'è un bel modo di affrontare questo in scikit-imparare?
  2. In caso contrario, questo comportamento è desiderato per qualsiasi motivo?

EDIT2:

aggiornamento, frammento di lavorare sulla base della risposta fornita da @ Chris

from sklearn.datasets import make_friedman1 
from sklearn import feature_selection 
from sklearn import pipeline 
from sklearn.grid_search import GridSearchCV 
from sklearn.svm import SVR 


class MyPipe(pipeline.Pipeline): 

    def fit(self, X, y=None, **fit_params): 
     """Calls last elements .coef_ method. 
     Based on the sourcecode for decision_function(X). 
     Link: https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/pipeline.py 
     ---------- 
     """ 
     super(MyPipe, self).fit(X, y, **fit_params) 
     self.coef_ = self.steps[-1][-1].coef_ 
     return self 


X, y = make_friedman1(n_samples=50, n_features=10, random_state=0) 

# Without Pipeline 
est = SVR(kernel="linear") 
selector = feature_selection.RFE(est) 
clf = GridSearchCV(selector, param_grid={'estimator__C': [1, 10, 100]}) 
clf.fit(X, y) 
print(clf.grid_scores_) 

# With Pipeline 
est = MyPipe([('svr', SVR(kernel="linear"))]) 
selector = feature_selection.RFE(est) 
clf = GridSearchCV(selector, param_grid={'estimator__svr__C': [1, 10, 100]}) 
clf.fit(X, y) 
print(clf.grid_scores_) 
+0

Vorrei approfondire il codice sorgente per verificare quale catena di eventi porta a RuntimeError. È abbastanza probabile che tu possa essere in grado di sovrascrivere le proprietà dell'oggetto di ritorno pertinente e semplicemente aggiungere nuovamente le variabili, ad esempio, se sono uguali quando vengono restituite da SVR(). In ogni caso, make_pipeline() potrebbe non restituire lo stesso tipo di oggetto di SVR(). – noumenal

risposta

2

Si è verificato un problema con l'utilizzo della pipeline.

Una conduttura funziona come segue:

primo oggetto viene applicato ai dati quando si chiama .fit (x, y), ecc Se questo metodo espone un metodo .transform(), questo viene applicato e questa uscita è usato come input per la fase successiva.

Una pipeline può avere qualsiasi modello valido come oggetto finale, ma tutti i precedenti DEVONO esporre un metodo .transform().

Proprio come un tubo: si alimentano i dati e ogni oggetto nella pipeline prende l'output precedente e fa un'altra trasformazione su di esso.

Come possiamo vedere,

http://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.RFE.html#sklearn.feature_selection.RFE.fit_transform

RFE espone un metodo transform, e così dovrebbe essere incluso in cantiere stesso. E.g.

some_sklearn_model=RandomForestClassifier() 
selector = feature_selection.RFE(some_sklearn_model) 
pipe_params = [('std_scaler', std_scaler), ('RFE', rfe),('clf', est)] 

Il tuo tentativo presenta alcuni problemi. In primo luogo, stai tentando di ridimensionare una porzione dei tuoi dati. Immagina di avere due partizioni [1,1], [10,10]. Se normalizzo per mezzo della partizione, perdo le informazioni che la mia seconda partizione è significativamente al di sopra della media. Dovresti ridimensionare all'inizio, non nel mezzo.

In secondo luogo, SVR non implementa un metodo di trasformazione, non è possibile incorporarlo come elemento non finale in una pipeline.

RFE accetta un modello che si adatta ai dati e quindi valuta il peso di ciascuna funzione.

EDIT:

È possibile includere questo comportamento se lo si desidera, avvolgendo il gasdotto sklearn nella propria classe. Quello che vogliamo fare è quando adattiamo i dati, recuperiamo l'ultimo metodo .coef_ degli stimatori e li memorizziamo localmente nella nostra classe derivata con il nome corretto. Ti suggerisco di esaminare il codice sorgente su github in quanto si tratta solo di un primo avvio e verrebbero probabilmente richiesti più errori di controllo ecc. Sklearn utilizza un decoratore di funzioni chiamato @if_delegate_has_method che sarebbe una cosa utile da aggiungere per garantire che il metodo sia generalizzato. Ho eseguito questo codice per assicurarmi che funzioni, ma niente di più.

from sklearn.datasets import make_friedman1 
from sklearn import feature_selection 
from sklearn import preprocessing 
from sklearn import pipeline 
from sklearn.grid_search import GridSearchCV 
from sklearn.svm import SVR 

class myPipe(pipeline.Pipeline): 

    def fit(self, X,y): 
     """Calls last elements .coef_ method. 
     Based on the sourcecode for decision_function(X). 
     Link: https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/pipeline.py 
     ---------- 
     """ 

     super(myPipe, self).fit(X,y) 

     self.coef_=self.steps[-1][-1].coef_ 
     return 

X, y = make_friedman1(n_samples=50, n_features=10, random_state=0) 

est = SVR(kernel="linear") 

selector = feature_selection.RFE(est) 
std_scaler = preprocessing.StandardScaler() 
pipe_params = [('std_scaler', std_scaler),('select', selector), ('clf', est)] 

pipe = myPipe(pipe_params) 



selector = feature_selection.RFE(pipe) 
clf = GridSearchCV(selector, param_grid={'estimator__clf__C': [2, 10]}) 
clf.fit(X, y) 

print clf.best_params_ 

se qualcosa non è chiaro, si prega di chiedere.

+0

Grazie a @Chris per la tua risposta. Non ero chiaro descrivendo il problema. Mi chiedo in particolare come accedere agli attributi "coef_" o "feature_importances_" di uno stimatore che sembrano essere nascosti dalla pipeline. – hubi86

+0

la mia modifica lo indirizza ora. In bocca al lupo. – Chris

0

penso che tu avessi un modo leggermente diverso di costruire la pipeline di quello che è stato elencato in il pipeline documentation.

Stai cercando questo?

X, y = make_friedman1(n_samples=50, n_features=10, random_state=0) 

est = SVR(kernel="linear") 

std_scaler = preprocessing.StandardScaler() 
selector = feature_selection.RFE(est) 
pipe_params = [('feat_selection',selector),('std_scaler', std_scaler), ('clf', est)] 
pipe = pipeline.Pipeline(pipe_params) 

param_grid = dict(clf__C=[0.1, 1, 10]) 
clf = GridSearchCV(pipe, param_grid=param_grid, cv=2) 
clf.fit(X, y) 
print clf.grid_scores_ 

vedere anche questo useful example per combinare le cose in una pipeline. Per l'oggetto RFE, ho appena usato lo official documentation per la sua costruzione con lo stimatore SVR - Ho quindi inserito l'oggetto RFE nella pipeline nello stesso modo in cui lo avevi fatto con gli oggetti scaler e stimator.

+0

Grazie per la risposta, ma la soluzione è diversa da quella che intendevo. Flusso di lavoro: 1. Durante le funzioni GridSearchCV vengono selezionate utilizzando 'RFE (SVR())' con il valore predefinito di 'C'. 2. Quindi, quelle funzioni selezionate vengono ridimensionate. 3. 'SVR()' è dotato di un parametro da 'param_grid'. Il flusso di lavoro desiderato è il seguente: 1. Durante le funzioni GridSearchCV vengono ridimensionate. 2. 'SVR()' è dotato di un parametro da 'param_grid'. 3. Quindi, le funzioni con i pesi più piccoli vengono eliminate dal modello. 4. I punti 1-3 vengono ripetuti fino al raggiungimento del numero desiderato di funzioni da selezionare. – hubi86