読者です 読者をやめる 読者になる 読者になる

データサイエンスしてみる

新米エンジニアがデータサイエンスを勉強する。機械学習とかRとかPythonとか

バンディットアルゴリズム ε-Greedyモデル

強化学習 機械学習

前回バンディットアルゴリズムの全体について見てみました。
grahamian.hatenablog.com

今回はバンディットアルゴリズムの基本であるε-Greedyモデルを見ていきます。

前回、バンディットアルゴリズムでは探索と活用が重要だと言いました。
ε-Greedyモデルでは0から1の乱数を取り、それがεを超えるか否かで探索するか活用するか決めます。

例えば、3本の腕があり、報酬の期待値が最も高い状況を考えます。
活用ではこの腕を引きます。
探索であればこの腕以外を引きます。
探索時に他のどの腕を開くかはランダムです。

ここで乱数を取ります。
0から1の乱数です。
事前に設定したεより高ければ探索、低ければ活用します。
つまりεの確率で探索、1-εの確率で活用するわけですね。

これを繰り返し行うことで次第に高い値が得られた腕が活用されることになります。

このアルゴリズムは非常にシンプルで、バンディットアルゴリズムの考え方がわかりやすいです。
バンディットアルゴリズムは最大の利益を得ることが目的でした。
そのために高い報酬が得られる腕を選びつつ、効率的に他の腕を探索することが重要です。
ε-Greedyモデルでは、探索する閾値をεというパラメータを用いて表現していました。

さて、ε-Greedyモデルはシンプルですが、シンプルゆえに問題点がある手法です。
問題の1つとして、たまたま高い報酬を得られた腕をずっと評価し続けてしまいます。
これは腕について報酬の確率分布について評価しないことに起因します。

これは割りと大きな問題で、実行するたびに失敗する確率が存在することを示しています。
そこでこれを改善したsoftmax法があります。

次回はこのsoftmax法を見てみましょう。

バンディットアルゴリズムって何?

機械学習 強化学習

なんかバンディットアルゴリズムというものがすごいらしいです。
勉強したことを少し書き溜めてみます。

バンディットアルゴリズムとは?
目の前にスロットが何台かあるとしましょおう。
それぞれのスロットには当たりの確率がそれぞれ設定されています。
もちろん、こっちは当たりの確率が高い台で遊びたいですよね。
でも使えるお金には限りがあります。
そこで、限られた条件の中で最大の利益を得るにはどうしたらいいか?というアルゴリズムが考えられました。
それがバンディットアルゴリズムです。

バンディットアルゴリズムは活用と探求にわけられます。
活用は良いと考えられる台で遊ぶことです。
探求は良い台を探すことです。

どの割合でそれぞれを行うか、これが肝になります。

よく似た手法としてA/Bテストが挙げられます。
A/Bテストはテスト対象をランダムに選び、その結果を利用するものです。
A/Bテストの難点はテスト回数が多くないと良い台を選ぶことができないことです。
無限大の試行回数があれば最も良い結果が得られますが、実際の問題では制約があります。
そのため、試行回数の限界があるため、十分な結果が得られないことがあります。
バンディットアルゴリズムならば少ない試行回数でもA/Bテストよりも効率良く、良い結果を得ることができます。
もちろん、バンディットアルゴリズムにも問題点はありますが。

次回は具体的なバンディットアルゴリズムの手法について見てみます。

gensimでトピックモデルを実装してみる

Python 機械学習 自然言語処理

自然言語処理のライブラリはpythonでは多々ありますが、gensimを今回は使います。
以前もgensimはWord2Vecを使うために使いましたね。
grahamian.hatenablog.com

今回はトピックモデルを実装するために使います。
とはいえ、作るだけならコードは3行で済みます。

こちらを参考に実装しました。
qiita.com

import gensim 
corpus = corpora.lowcorpus.LowCorpus('text.txt')
lda = gensim.models.ldamodel.LdaModel(corpus=corpus, num_topics=20, id2word=corpus.id2word)

text.txtはスペースで単語を区切ったテキストファイルです。
事前にMecabで分ち書きをして名詞だけにしてあります。

実装はこれだけで完了です。
あとはLdaModelを使って文書分類の推定されたトピックIDを見たり、トピックにおけるトークンの出現率を見ることができます。
また、num_topicsを変えることで分類するトピック数を変えることもできます。

トピックモデルは抽象的な理解は簡単ですが、LDAトピックモデルは統計の知識がないと理解が難しいです。
でも実装がこんな簡単にできるなんて最高ですね。

anacondaのlibraryをPyCharmでimportする

Python 機械学習

タイトルどおりです。
最近PyCharmを使い初めたのですが、importで詰まったので書いておきます。

PyCharmで普通にプロジェクトを作成すると標準のpython環境を使おうとするみたいです。
で、CreateProjectのときにProject Interpreterからanaconda環境のpythonを選択する必要があります。
普通だったら"//anaconda/bin/python"にあります。

ちなみにプロジェクトを作ったあとに変更する場合は
Preference
>Project
>Project Interpreter
で選択できます。

選択するとanacondaのlibraryが一覧に表示されるはずです。
この状態でOKをクリックでanaconda環境のlibraryがimportできるようになります。
ちなみに反映されるまで数分時間がかかるみたいです。
すぐに反映されなくて「なんでやねん!」とか思っても焦らないで待ってれば反映されます。

PythonでMeCabを使う

Python 自然言語処理

自然言語処理では定番となったmecabpythonで使います。
以前はpython用のmecabがなかったので独自にコンパイルされたものを導入していました。
今はpipで簡単に使えるようになったので、覚書として書いておきます。

ちなみに私はanacondaによるpython3系の環境です。

brew install mecab
brew install mecab-ipadic
pip install mecab-python3

いろんなとこを見るとpipでinstallだけで使えるって書いてあったとこもあったのですが、上手くいきませんでした。
ちょっと検索してみたらbrewmecabを入れてるとこがあったので、それもやったら上手くいきました。

導入できたらテストしてみましょう。

python
import MeCab
mecab = MeCab.Tagger("-Ochasen")
print(mecab.parse("あいうえお"))

これで解析できたらOKです。

pipは便利ですね。

word2vecしてみる

Python 機械学習 自然言語処理

2014年くらいに流行ったツールであるword2vecを使ってみます。
word2vecの詳細は省きますが、簡単に言うと、単語を任意のベクトルに変換するものです。
skip-gramかCountinuous Bag of Wordsモデルに基づいてベクトル化されます。
簡単に言うと、ある単語のまわりの単語をもとにベクトル化されるわけですね。

というわけで、さっそく使ってみます。
今回も先人の知恵を拝借しております。感謝!
Python で「老人と海」を word2vec する · m0t0k1ch1st0ry

流れとしては
gensimをpip
>訓練用文書を読み込む
>モデルを生成
>類似単語を見てみる
>楽しい! ✌('ω'✌ )三✌('ω')✌三( ✌'ω')✌

さてさて、普通にpipでgensimをインストールします。

pip install gensim

念のため、importして確認しておきます。

import gensim

エラーが出なければOKです。
さっそく訓練用文章を使いましょう。
今回は公式のテスト用コーパスであるtext8を使いました。

こんな感じ。

from gensim.models import word2vec
sentences = word2vec.Text8Corpus(r"text8")
model = word2vec.Word2Vec(sentences, size=200, min_count=20, window=15)
model.save("sample.model")

これで訓練が始まります。
PCのスペックに依りますが、1時間はかからないと思います。
MBPだと10分もかかりませんでしたね。

終わるとカレントディレクトリにsample.modelというファイルができます。
これが学習させた分類機になるわけですね。

さっそく類義語検索をしてみましょう。

model = word2vec.Word2Vec.load("sample.model")
def s(posi, nega=[], n=10):
    cnt = 1 # 表示した単語の個数カウント用
    result = model.most_similar(positive = posi, negative = nega, topn = n)
    for r in result:
        print (cnt,' ', r[0],' ', r[1])
        cnt += 1

if __name__ == '__main__':
    word = 'word'
    s([word])

これだけで類義語が検索されます。
類似度はcos類似度みたいですね。

非常に簡便かつ高速に類義語検索ができるので実用性が高そうです。
ただ、日本語だと英語よりうまくいかない場合がある感じがします。
入力させる文書について量を増やしたり、ジャンルごとにわけるなどの工夫が必要そうです。

どちらにせよ、学習が高速なのでいろいろ遊べるオモチャって感じです。

KH Coderのオプション「Ward・郡平均・最短距離法」って?

KHコーダー 自然言語処理

前回はKH Coderを使って簡単な自然言語解析をしてみました。
grahamian.hatenablog.com

今回はKH CoderのオプションにあるWard・郡平均・最短距離法について書いてみます。

Ward・郡平均・最短距離法ってそもそも何?

そもそもWard・郡平均・最短距離法とは階層クラスター解析の際に使われる手法の一つです。
クラスタリングする方法はいくつかありますが、階層・非階層の2つがあります。
階層クラスタリングは予め決めた条件を満たすようにクラスタリングする方法です。
非階層クラスタリングは予め決めたクラスター数になるようにクラスタリングする方法です。
それぞれには次のような特徴があります。
階層クラスタリングは収束条件が決まっているため何度計算しても毎回同じようになります。
一方、非階層では初期状態によって結果のゆらぎが存在します。
計算の精度を考えると階層クラスタリングだけでいいような気がしますね。
でも階層クラスタリングはデータ量が増えると計算時間が爆発します。
そのためビッグデータ解析では非階層クラスタリングが主に使われています。

まあKH Coderでは階層クラスタリング使ってますが。

さて、そんな階層クラスタリングをするときの収束条件を決めるのがWard法とかです。

Ward法とは?

Ward法は「重心」を意識した方法です。
あるクラスタの重心をWとします。
次に2クラスターが結合することを仮定したとき生じる重心W'を考えます。
このとき、元々のクラスタの重心Wと要素との距離の二乗和と、結合後クラスタの重心W'と要素との距離の二乗和の差を算出します。
この二乗和の差が最小になるように結合していくのがWard法です。
計算量は多いですが感度が高いので一般的に使用されている手法です。

郡平均法とは?

郡平均法は各クラスタの間における要素距離の平均をクラスタ距離として計算します。
この距離を最小にする手法です。

最短距離法とは?

最短距離法はクラスタの要素距離で最も近いものをクラスタ距離とします。
これは上述の2手法に比べて計算量が非常に少ないです。
しかし、クラスタが順番に結合してしまう「鎖効果」が発生しやすいです。
そのため分類の感度が低い方法となっています。

まとめ

さて、今回は簡単にKH Coderにでてくるクラスタリングのオプションについて簡単に書いてみました。
難しい数学も無いので割りと直感的に理解できる範囲で良かったです。
クラスタリングは非常に便利で強力な手法なのでガンガン身につけて行きたいですね。