Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
47
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

scikit-learnでモデルのハイパーパラメータチューニングをしよう!

ハイパーパラメータチューニングって?

モデルによってあらかじめ決めなきゃいけないパラメータがあります。
(例えばk-meansのクラスタ数や、SVCの正則化項の強さ、決定木の深さなど)

それを『ハイパーパラメータ』というのですが、困ったことに同じモデルだとしてもハイパーパラメータの値によって精度が大幅に変わることもあります。

それをうまく、学習データを用いて決めてしまおうというのが、ハイパーパラメータチューニングなのです!!

グリッドサーチとランダムサーチ

そのチューニング手法の内、今回扱うのは、グリッドサーチとランダムサーチの2つです。
ざっくりいいますと、ハイパーパラメータαがあるとすると以下の流れで実行します。

・グリッドサーチは、あらかじめαの範囲(ex. 0,1,2,3,4,5など)を指定して、実際にそのパラメータでモデルの精度を出してみて、一番いいやつをパラメータにする。

・ランダムサーチは、あらかじめαが従う分布(ex. 平均0, 標準偏差1の正規分布など)を指定して、そこからランダムに取り出し、実際にそのパラメータでモデルの精度を出してみて、一番いいやつをパラメータにする.

Screen Shot 2017-02-25 at 22.37.35.png

以上のように、両者ともハイパーパラメータαをそのままあてずっぽうで決めるという手順ではなく、
その前に、範囲や分布を決め、実際の訓練データを使って決めるという手順をとっていることがわかります。(より詳細については、参考文献をご覧になってください!)

Pythonコード

上記の2つがscikit-learnでは標準装備されているので利用していきます!
python3.5.1, scikit_learn-0.18.1でのコードです。

今回は、UCIのMachine Learning Repositoryからデータをとって、RandomForestClassifierの2つの分類器を使用して、パラメータチューニングをしています。
コードの全容はgithubにアップロードしています.

STEP1 データをUCIリポジトリからダウンロード

Grid_and_Random_Search.ipynb
 df = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases'
                  '/breast-cancer-wisconsin/wdbc.data', header=None)

分かりやすくするために、予測したいカラムをTargetに、その他をa~にします。

Grid_and_Random_Search.ipynb
 columns_list = [] 
 for i in range(df.shape[1]):
     columns_list.append("a%d"%i) 
 columns_list[1] = "Target" 
 df.columns = columns_list

STEP2 データを分割

Grid_and_Random_Search.ipynb
 y = df["Target"].values
 X = df.drop(["a0","Target"],axis=1)

trainデータとtestデータに分割

Grid_and_Random_Search.ipynb
 #split X,y to train,test(0.5:0.5)
 from sklearn.cross_validation import train_test_split

 X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.5,random_state=2017)

STEP3 デフォルトの状態でのモデルの精度を検査してみる.

Grid_and_Random_Search.ipynb
 from sklearn.metrics import classification_report

 def model_check(model):
     model.fit(X_train,y_train)
     y_train_pred = classification_report(y_train,model.predict(X_train))
     y_test_pred  = classification_report(y_test,model.predict(X_test))

     print("""【{model_name}】\n Train Accuracy: \n{train}
           \n Test Accuracy:  \n{test}""".format(model_name=model.__class__.__name__, train=y_train_pred, test=y_test_pred))

print(model_check(RandomForestClassifier()))
出力結果1(デフォルト)
    [RandomForestClassifier]
     Train Accuracy: 
                 precision    recall  f1-score   support

              B       1.00      1.00      1.00        67
              M       1.00      1.00      1.00        75

    avg / total       1.00      1.00      1.00       142


     Test Accuracy:  
                 precision    recall  f1-score   support

              B       0.89      0.93      0.91        72
              M       0.93      0.89      0.91        70

    avg / total       0.91      0.91      0.91       142

Trainデータの正答率は1.0、Testデータの正答率は0.91だということがわかりました。
ここからグリッドサーチとランダムサーチを実装していきます。
以降は参考文献3を参考にしています。

STEP4 グリッドサーチ

Grid_and_Random_Search.ipynb
 #Grid search

 from sklearn.grid_search import GridSearchCV

 # use a full grid over all parameters
 param_grid = {"max_depth": [2,3, None],
              "n_estimators":[50,100,200,300,400,500],
              "max_features": [1, 3, 10],
              "min_samples_split": [2, 3, 10],
              "min_samples_leaf": [1, 3, 10],
              "bootstrap": [True, False],
              "criterion": ["gini", "entropy"]}

 forest_grid = GridSearchCV(estimator=RandomForestClassifier(random_state=0),
                 param_grid = param_grid,   
                 scoring="accuracy",  #metrics
                 cv = 3,              #cross-validation
                 n_jobs = 1)          #number of core

 forest_grid.fit(X_train,y_train) #fit

 forest_grid_best = forest_grid.best_estimator_ #best estimator
 print("Best Model Parameter: ",forest_grid.best_params_)
出力結果2(グリッドサーチ)
    [RandomForestClassifier]
     Train Accuracy: 
                 precision    recall  f1-score   support

              B       0.99      0.99      0.99        67
              M       0.99      0.99      0.99        75

    avg / total       0.99      0.99      0.99       142


     Test Accuracy:  
                 precision    recall  f1-score   support

              B       0.96      0.89      0.92        72
              M       0.89      0.96      0.92        70

    avg / total       0.92      0.92      0.92       142

合計の正答率や、f1-scoreなど全ての精度が上昇しています!!

STEP5 ランダムサーチ

ランダムサーチでは、scipyを使ってパラメータの従う分布を表現する。
今回は、イテレーション回数をグリッドサーチと同様にしています。

Grid_and_Random_Search.ipynb
#Random search
from sklearn.grid_search import RandomizedSearchCV
from scipy.stats import randint as sp_randint

param_dist = {"max_depth": [3, None],                  #distribution
              "n_estimators":[50,100,200,300,400,500],
              "max_features": sp_randint(1, 11),
              "min_samples_split": sp_randint(2, 11),
              "min_samples_leaf": sp_randint(1, 11),
              "bootstrap": [True, False],
              "criterion": ["gini", "entropy"]}

forest_random = RandomizedSearchCV( estimator=RandomForestClassifier( random_state=0 ),
                                    param_distributions=param_dist,
                                    cv=3,              #CV
                                    n_iter=1944,          #interation num
                                    scoring="accuracy", #metrics
                                    n_jobs=1,           #num of core
                                    verbose=0,          
                                    random_state=1)

forest_random.fit(X,y)
forest_random_best = forest_random.best_estimator_ #best estimator
print("Best Model Parameter: ",forest_random.best_params_)
出力結果3(ランダムサーチ)
    [RandomForestClassifier]
     Train Accuracy: 
                 precision    recall  f1-score   support

              B       1.00      1.00      1.00        67
              M       1.00      1.00      1.00        75

    avg / total       1.00      1.00      1.00       142


     Test Accuracy:  
                 precision    recall  f1-score   support

              B       0.94      0.92      0.93        72
              M       0.92      0.94      0.93        70

    avg / total       0.93      0.93      0.93       142

デフォルトの場合と比べると、どの項目も2%増加していることがわかりました!

まとめ

グリッドサーチ、ランダムサーチともに精度が良くなりました!
ただ、おそらく今回は元々精度が高いようなデータを選んだため、効果が見えづらくなってしまったのではないかと思います。
精度が良くないようなデータに試してみるとチューニングの効果が分かりやすいかもしれません。

コード全容は、githubにアップロードしてあります。

参考文献
1. Bergstra, J., & Bengio, Y. (2012)
2. http://qiita.com/SE96UoC5AfUt7uY/items/c81f7cea72a44a7bfd3a
3. http://scikit-learn.org/stable/auto_examples/model_selection/randomized_search.html

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
47
Help us understand the problem. What are the problem?