2018年07月20日

ランダムフォレストを使って分類してみた

エモトです.暑い日が続きますね.暑いのが苦手なので一苦労です.さて先週ポケモン映画を行きました.テレビ版は最近見なくなってしまったのですが,劇版特有のパラレル設定のおかげで「関係性がわからん」といこともなくサクッと見れました.次はあの名作のリメイク,これは赤緑世代なのでいまから楽しみです.

今回はランダムフォレスト(Random Forest,以下RF)についてです.RFは,簡単に言うと複数の決定木を束ねたものになります.精度も高く,回帰や分類に使用されてます.いま深層学習が流行っていますが,すべてが深層学習に適しているとは限りません.まずはRFで検証するのも良いアプローチだと思います.

以下,RFの分類についての実装を紹介します(エラーや例外の処理は省いています).今回も scikit-learn を使って行きます.まずは必要な import をまとめておきます.
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
from sklearn.metrics import f1_score
from sklearn.metrics import confusion_matrix
from sklearn.externals import joblib
学習です.特に難しいことはなく,訓練データの入出力データを渡して学習させます.データ規模も特別大きくなければ,学習は短時間で行われると思います.また学習したRFはファイルに保存しています.
def train_random_forest(x_train, y_train, save_name: str):

    # RFの定義
    forest = RandomForestClassifier(n_estimators=100, n_jobs=-1)

    # 学習
    forest.fit(x_train, y_train)

    # 保存
    joblib.dump(forest, save_name, compress=True)

    return forest
学習したRFの予測値や精度をテスト(検証)します.また,RFは入力データの特徴量の重要度を求めることができます.あまり重要度が高くない特徴量は入力データから削除して,より効率化を行うことができます.下記例では,特徴量名は適当に設定しているので実際は自信の環境に合わせる必要があります.
def test_random_forest(x_test, y_test, model_name: str):

    # RFの読み込み
    forest = joblib.load(model_name)

    # 予測データの作成
    y_predict = forest.predict(x_test)
    y_proba = forest.predict_proba(x_test)

    # 正解率
    acc_score = accuracy_score(y_test, y_predict)
    print("acc: {}".format(acc_score))

    # F値と混同行列
    f1_sc = f1_score(y_test, y_predict)
    conf_mat = confusion_matrix(y_test, y_predict)
    print('f1 score: {}'.format(f1_sc))
    print('Confusion matrix: {}'.format(conf_mat))

    # 特徴量の重要度
    # 特徴量名があればさらに見やすい結果になります
    # ここで定義した特徴量名は適当です
    feature_names = ["feature0", "feature1", "feature2"]
    importances = forest.feature_importances_
    for (f, i) in zip(feature_names, importances):
        print("{}, {}".format(f, i))
また,RFに関わらず,不均衡データを取り扱う場合は注意が必要です.不均衡が大きければ,データ数が多いクラスに影響され学習されます.一見精度は高くなりますがF値が下がった結果になり,実用できるレベルにはなりません.前処理として,データを調整するのもありますが,RFには不均衡データ向けの学習オプションがあります.
forest = RandomForestClassifier(class_weight="balanced")
しかしながら,あまり変化があるようには見えませんでした.リンク先を失念していまいましたが,内部実装からもあまり効果ないという記事を見たことがあります.また,別の方法として,imbalanced-learn のRFを使用する方法もあります.
from imblearn.ensemble import BalancedBaggingClassifier
forest = BalancedBaggingClassifier(n_estimators=100,n_jobs=-1)
これは scikit-learn とほぼほぼ同じメソッドや変数が使用できるので簡単に入れ替えができます(ただ,特徴量の重要度がなかったと思います).ちなみに,私が検証したデータだと,これを使用しても大きく結果が変わることはありませんでした.前処理でデータ割合を調整するのが最も効果がありました.
posted by Seesaa京都スタッフ at 12:00| Comment(0) | 機械学習 | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント: