毎日テキストマイニング

180日間、毎日テキストマイニングをするブログです

2018/8/14【52日目】グリップリサーチをしてみる

現状の正解率もわかったところで、ランダムフォレストのパラメーターを調整していきたいと思います。今はチュートリアルの通りのRandomForestClassifier(n_estimators = 100) しか設定していませんが、これ以外にも多くのパラーメーターがあるみたいです。

3.2.4.3.1. sklearn.ensemble.RandomForestClassifier — scikit-learn 0.19.2 documentation

さらっと見てみるとこんな感じです。それほど理解していないので説明はかなりザクっとしています。

  • n_estimators : integer, optional (default=10) ツリーの数
  • criterion : string, optional (default=”gini”) データの分割方法
  • max_features : int, float, string or None, optional (default=”auto”) 最大の特徴量
  • max_depth : integer or None, optional (default=None) ツリーの深さ。何も措定しない場合は全部のみる
  • min_samples_split : int, float, optional (default=2) 分割するために最低限必要とするサンプル
  • min_samples_leaf : int, float, optional (default=1) 葉を作るために最低限必要とするサンプル
  • min_weight_fraction_leaf : float, optional (default=0.) 合計値に対する最低限の重み
  • max_leaf_nodes : int or None, optional (default=None) 最大の葉を数を指定
  • min_impurity_split : float, 木の成長を止めるためのしきい値
  • min_impurity_decrease : float, optional (default=0.) ノードが分割するしきい値
  • bootstrap : boolean, optional (default=True) bootstrapを使うかどうかの選択
  • oob_score : bool (default=False) 精度を推定するためにout-of-bagサンプルを使用するかどうかの選択
  • n_jobs : integer, optional (default=1) 並列処置の数を指定する
  • random_state : int, RandomState instance or None, optional (default=None) シード値を設定するかどうかの選択(乱数を固定するかどうか)
  • verbose : int, optional (default=0) ツリーの成長の冗長性をコントロールする
  • warm_start : bool, optional (default=False) すでに学習をしたモデルに新しく学習させるかどうか
  • class_weight : dict, list of dicts, “balanced”, それぞれのクラスに重みをつけるかどうか

これらのパラメーターになんの値を設定すればいいのか全然わからないので、グリッドサーチという総当たりを行いたいと思います。

グリッドサーチの詳細はこちら。

3.2. Tuning the hyper-parameters of an estimator — scikit-learn 0.19.2 documentation

グリッドサーチとは

パラメーターを事前に辞書型で設定しておき、それをモデルに順番に当てはめるだけです

from sklearn.model_selection import GridSearchCV

parameters = {
        'n_estimators'      : [30, 50, 100, 300],
        'max_features'      : [10, 20, 30],
        'random_state'      : [0],
        'n_jobs'            : [1],
        'min_samples_split' : [10, 30, 50, 100],
        'max_depth'         : [10, 30, 50, 100]
}

clf1 = GridSearchCV(RandomForestClassifier(), parameters)
clf1.fit(train_X, train_y)
 
print(clf1.best_estimator_)

おそらく順番に実行していますので、かなり時間がかかります。

待っている間に暇ですので、AKBの新曲『センチメンタルトレイン』を聞いてみたのですが、なんとなく乃木坂でも聞いたことありますね。グッグって見たらmパクリ騒動の話があったらしいです。

全然終わる気配がしないので、FlaskというPython製Webアプリケーションフレームワークの公式サイトでも見ていきます。

Flaskへ ようこそ — Flask v0.5.1 documentation

まずはインストールしろ、と書いてありますので、インストールをします。

sudo easy_install Flask

インストールできたか確認。

$ flask --version
Flask 0.12.2
Python 3.6.2

Flaskをインストールできました。

グリッドサーチの方も終わったぽいです。 だいたい15分くらいかかっていました。 結果はこんな感じです。

RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
            max_depth=100, max_features=30, max_leaf_nodes=None,
            min_impurity_decrease=0.0, min_impurity_split=None,
            min_samples_leaf=1, min_samples_split=10,
            min_weight_fraction_leaf=0.0, n_estimators=30, n_jobs=1,
            oob_score=False, random_state=0, verbose=0, warm_start=False)

max_depthとmax_featuresは最大の値がベストとされていますね。n_estimatorsは最低の値がベストとされています。最初のパラメーターを若干ミスったような気がします。

パラメータを下記で設定し直します。

parameters = {
        'n_estimators'      : [5, 10, 30],
        'max_features'      : [30, 60, 100],
        'random_state'      : [0],
        'n_jobs'            : [1],
        'min_samples_split' : [5, 10],
        'max_depth'         : [100, 150, 200]
}
RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
            max_depth=100, max_features=30, max_leaf_nodes=None,
            min_impurity_decrease=0.0, min_impurity_split=None,
            min_samples_leaf=1, min_samples_split=5,
            min_weight_fraction_leaf=0.0, n_estimators=30, n_jobs=1,
            oob_score=False, random_state=0, verbose=0, warm_start=False)

そんなに変わっていないということは、やはりこれがベストなんですかね? そもそもとしましてはグリップリサーチは万能ではないとのことですが、ひとまずこのパラメーターを設定してみます。

forest = RandomForestClassifier(n_estimators=30,
                                max_depth=100,
                                max_features=30, 
                                max_leaf_nodes=None,
                                min_impurity_decrease=0.0,
                                min_impurity_split=None,
                                min_samples_leaf=1,
                                min_samples_split=5,
                                min_weight_fraction_leaf=0.0,
                                oob_score=False,
                                random_state=0,
                                verbose=0,
                                n_jobs=1,
                               ) 
forest = forest.fit(train_data_features, train["name_int"])

学習させ直したところで、k分割交差検証をさせてみます。

from sklearn.model_selection import cross_val_score
print(cross_val_score(forest, train_data_features, train['name_int'], cv=20))
[ 0.96039604  0.96039604  0.96039604  0.96039604  0.97029703  0.96039604
  0.96        0.96        0.96        0.96        0.96        0.96        0.96
  0.96        0.96969697  0.96969697  0.96969697  0.96969697  0.97979798
  0.96969697]

お、全体的に1分上がって、9割6分になっています。

y_preds = forest.predict(train_X)
confusion_matrix(test_y, y_preds)
array([[940,  26],
       [ 34,   0]])

昨日のがこちら

array([[926,  31],
       [ 43,   0]])

数値が変わっていますが、改善されたのかよくわからないですね。

今日の結果

今日のAKBの呟きは64件でした。 最後という単語が並んでいましたので、誰か卒業するのかと思いました。

f:id:rimt:20180815004113p:plain

{'嬉しい': 9, '可愛い': 6, '楽しい': 5, 'すごい': 4, 'ない': 3, '優しい': 2, '明るい': 1, '暗い': 1, 'やすい': 1, 'うい': 1, 'いい': 1, '遅い': 1, '詳しい': 1, 'よい': 1, 'かわいい': 1, '熱い': 1, '凄い': 1, '長い': 1, '良い': 1, 'うまい': 1, '面白い': 1, 'ぽい': 1})
'公演': 19, '最後': 13, '私': 12, '応援': 12, 'お願い': 11, '今日': 10, '嬉しい': 9, 'ん': 9, 'ちゃん': 9, '生誕': 8, '祭': 8, 'おりん': 8, '皆さん': 7, '日': 7, 'チームフォー': 7, '手': 7, 
'する': 44, '公演': 19, 'なる': 14, '最後': 13, '私': 12, '応援': 12, '見る': 12, 'お願い': 11, '今日': 10, '嬉しい': 9, 'ん': 9, 'ちゃん': 9, '生誕': 8, '祭': 8, 'おりん': 8, 'てる': 8, 'くださる': 8, 'いる': 8,