2018年08月06日

「自然言語と機械学習」という題目で発表しました

エモトです。先日「カメラを止めるな!」を見てきました。なんか評判がいいホラー映画?自主映画?程度の知識で見に行きましたが、ど肝を抜かれました。前半で感じた幾つもの違和感は、後半でそれぞれ拾われていく。「まじかーそうだったのかー」と面白い。あとカメアシの赤メガネがかわいいです。上映館が増えているようなので、みなさん見るのをおすすめします。

運営協力している Kyoto.LT 第21回 にて「自然言語と機械学習」というタイトルで発表しました。自然言語と銘打ってますが、これまでの経験を元に計算用にデータ化する場合にどうするかを簡単にまとめました。後半はその特徴量を用いて、RCNNでレーティング分類をした分類実験を簡単に紹介しています。

posted by Seesaa京都スタッフ at 12:00| Comment(0) | 機械学習 | このブログの読者になる | 更新情報をチェックする

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) | 機械学習 | このブログの読者になる | 更新情報をチェックする

2018年06月15日

Pythonで自作ライブラリのパスを設定する

エモトです.みなさまDP2はご覧になりましたでしょうか.こまけぇことはいいんだよのAAがよく似合うエピローグ(いや全編でか),これが映画なんだよと圧巻でした.

Pythonに限らず,作成したメソッドやライブラリを他の自プロジェクトに使いたいことはあると思います.今回はそんなときのお話です.

ライブラリを公開して,pip コマンドでインストール可能にすれば便利ですが,一般公開するまでもないものや,公開してはダメなものもあるので,今回はローカル環境でパスを設定します.

PYTHONPATH を設定すればできるようですが,私の環境は pyenv で作成しているのか,うまく反映されませんでした.
$ export PYTHONPATH="hogehoge/mylib"
そこで,すでにパスが通っているところに pthファイル を置いて,新たにパスを設定します.それらのパスは以下のようにして確認できます.
import sys
for path in sys.path:
  print(path)
pthファイルは site-packages に保存します.私の環境では以下のパスになりました.
/Users/user/.pyenv/versions/3.6.1/lib/python3.6/site-packages
次に,pth ファイル名を mylib.pth,設定したいパスを hogehoge/mylib としたとき,以下のようにすれば pth ファイルを追加できます.
pth_file = "mylib.pth"
pth_body = "hogehoge/mylib"
for path in sys.path:
  if ".pyenv" in path and path.endswith("site-packages") is True:
    save_path = os.path.join(path, pth_file)
    with open(save_path, "w") as f:
      f.write(pth_body)
また,ファイル追加をしたら,削除も用意した方もいいでしょう.ここは簡単にコマンドラインの引数から,削除を追加しました.
# $ python add_pth_file.py delete
if len(args) > 1 and args[1] == "delete":
  if os.path.exists(save_path):
    os.remove(save_path)
いまのところ,他プロジェクトでも使うライブラリは,このpthファイル作成と一緒に1つのリポジトリに入れて管理しています.新しい環境でも,gitクローンしたらパス追加コマンドを使えば,簡単にライブラリが使えるようになります.また,パス指定のところでディレクトリ位置を動的に取得して反映するように変更し,クローンを行うディレクトリに依存しないようにしています.
posted by Seesaa京都スタッフ at 12:00| Comment(0) | 機械学習 | このブログの読者になる | 更新情報をチェックする