2017-05-04 2 views
9

パイプラインについて引き続き調査します。私の目的は、パイプラインだけで機械学習の各ステップを実行することです。他のユースケースで私のパイプラインを適応させる方がより柔軟で簡単になります。だから私は何をすべきか:パイプラインでクラシファイアの後にメトリックを使用

  • ステップ1:数字にカテゴリ値を変換する
  • ステップ3:分類子
  • ステップ4:GridSearch
  • ステップ5:追加記入NaNが
  • ステップ2値メトリック(失敗)

ここでは私のコードです:

import pandas as pd 
from sklearn.base import BaseEstimator, TransformerMixin 
from sklearn.feature_selection import SelectKBest 
from sklearn.preprocessing import LabelEncoder 
from sklearn.model_selection import GridSearchCV 
from sklearn.model_selection import train_test_split 
from sklearn.ensemble import RandomForestClassifier 
from sklearn.pipeline import Pipeline 
from sklearn.metrics import roc_curve, auc 
import matplotlib.pyplot as plt 
from sklearn.metrics import confusion_matrix 
from sklearn.metrics import f1_score 


class FillNa(BaseEstimator, TransformerMixin): 

    def transform(self, x, y=None): 
      non_numerics_columns = x.columns.difference(
       x._get_numeric_data().columns) 
      for column in x.columns: 
       if column in non_numerics_columns: 
        x.loc[:, column] = x.loc[:, column].fillna(
         df[column].value_counts().idxmax()) 
       else: 
        x.loc[:, column] = x.loc[:, column].fillna(
         x.loc[:, column].mean()) 
      return x 

    def fit(self, x, y=None): 
     return self 


class CategoricalToNumerical(BaseEstimator, TransformerMixin): 

    def transform(self, x, y=None): 
     non_numerics_columns = x.columns.difference(
      x._get_numeric_data().columns) 
     le = LabelEncoder() 
     for column in non_numerics_columns: 
      x.loc[:, column] = x.loc[:, column].fillna(
       x.loc[:, column].value_counts().idxmax()) 
      le.fit(x.loc[:, column]) 
      x.loc[:, column] = le.transform(x.loc[:, column]).astype(int) 
     return x 

    def fit(self, x, y=None): 
     return self 


class Perf(BaseEstimator, TransformerMixin): 

    def fit(self, clf, x, y, perf="all"): 
     """Only for classifier model. 

     Return AUC, ROC, Confusion Matrix and F1 score from a classifier and df 
     You can put a list of eval instead a string for eval paramater. 
     Example: eval=['all', 'auc', 'roc', 'cm', 'f1'] will return these 4 
     evals. 
     """ 
     evals = {} 
     y_pred_proba = clf.predict_proba(x)[:, 1] 
     y_pred = clf.predict(x) 
     perf_list = perf.split(',') 
     if ("all" or "roc") in perf.split(','): 
      fpr, tpr, _ = roc_curve(y, y_pred_proba) 
      roc_auc = round(auc(fpr, tpr), 3) 
      plt.style.use('bmh') 
      plt.figure(figsize=(12, 9)) 
      plt.title('ROC Curve') 
      plt.plot(fpr, tpr, 'b', 
        label='AUC = {}'.format(roc_auc)) 
      plt.legend(loc='lower right', borderpad=1, labelspacing=1, 
         prop={"size": 12}, facecolor='white') 
      plt.plot([0, 1], [0, 1], 'r--') 
      plt.xlim([-0.1, 1.]) 
      plt.ylim([-0.1, 1.]) 
      plt.ylabel('True Positive Rate') 
      plt.xlabel('False Positive Rate') 
      plt.show() 

     if "all" in perf_list or "auc" in perf_list: 
      fpr, tpr, _ = roc_curve(y, y_pred_proba) 
      evals['auc'] = auc(fpr, tpr) 

     if "all" in perf_list or "cm" in perf_list: 
      evals['cm'] = confusion_matrix(y, y_pred) 

     if "all" in perf_list or "f1" in perf_list: 
      evals['f1'] = f1_score(y, y_pred) 

     return evals 


path = '~/proj/akd-doc/notebooks/data/' 
df = pd.read_csv(path + 'titanic_tuto.csv', sep=';') 
y = df.pop('Survival-Status').replace(to_replace=['dead', 'alive'], 
             value=[0., 1.]) 
X = df.copy() 
X_train, X_test, y_train, y_test = train_test_split(
    X.copy(), y.copy(), test_size=0.2, random_state=42) 

percent = 0.50 
nb_features = round(percent * df.shape[1]) + 1 
clf = RandomForestClassifier() 
pipeline = Pipeline([('fillna', FillNa()), 
        ('categorical_to_numerical', CategoricalToNumerical()), 
        ('features_selection', SelectKBest(k=nb_features)), 
        ('random_forest', clf), 
        ('perf', Perf())]) 

params = dict(random_forest__max_depth=list(range(8, 12)), 
       random_forest__n_estimators=list(range(30, 110, 10))) 
cv = GridSearchCV(pipeline, param_grid=params) 
cv.fit(X_train, y_train) 

私は、ロープカーブを印刷するのは理想的ではないことを認識していますが、今は問題ではありません。私はこのコードを実行すると

だから、私が持っている:

TypeError: If no scoring is specified, the estimator passed should have a 'score' method. The estimator Pipeline(steps=[('fillna', FillNa()), ('categorical_to_numerical', CategoricalToNumerical()), ('features_selection', SelectKBest(k=10, score_func=<function f_classif at 0x7f4ed4c3eae8>)), ('random_forest', RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini', 
      max_depth=None,...=1, oob_score=False, random_state=None, 
      verbose=0, warm_start=False)), ('perf', Perf())]) does not. 

私はすべてのアイデアに興味がある...

答えて

5

エラー状態として、あなたはGridSearchCVで得点パラメータを指定する必要があります。 (コメント欄での質問に基づいて)

使用

GridSearchCV(pipeline, param_grid=params, scoring = 'accuracy')

編集

あなたは(そしてすべてではないため、全体X_trainとy_trainためのROC、AUC曲線とF1を必要とする場合GridSearchCVの分割)は、Perfクラスをパイプラインから外しておく方がよいでしょう。

pipeline = Pipeline([('fillna', FillNa()), 
        ('categorical_to_numerical', CategoricalToNumerical()), 
        ('features_selection', SelectKBest(k=nb_features)), 
        ('random_forest', clf)]) 

#Fit the data in the pipeline 
pipeline.fit(X_train, y_train) 

performance_meas = Perf() 
performance_meas.fit(pipeline, X_train, y_train) 
+0

素晴らしい!しかし、私のロープカーブをこのようにプロットすることはできません。同じパイプラインで精度とf1スコアを得ることは可能でしょうか? –

+0

可能です。あなたは結果を得ていませんか?あなたのコードをさらに調べると、このコードを解いても別のエラーが出るようです。 –

+0

私の 'クラスPerf'を削除し、' cv = GridSearchCV(pipeline、param_grid = params、scoring = '精度')を呼び出すと、 cv.fit(X_train、y_train) '私は何もエラーがありません。私はroc、auc、f1_scoreを同じ実行で得る方法を見つけようとしています –

関連する問題