紙媒体で管理するとなくなりがちなのでブログで進捗などを管理することにしました
※殆どの記事は自分自身のためだけにかいています.他人に見せられるレベルには至っていません...

League of Legendsのチャンプ間の分析

pythonのライブラリnetworkxの勉強がてらにLeague of Legends(以後LoL)におけるチャンピオン間のネットワークを作った.
LoLとは世界的に人気のオンラインゲームであり,全10人のプレイヤーが5人,5人に分かれて戦い合う.
下のようなマップで相手の陣地の一番奥にあるオブジェクトを最初に壊したチームが勝利である.
f:id:umashika5555:20170822042549j:plain
下の動画はLoLのプロゲームで私が最も好きな試合である.
www.youtube.com

LoLでは始め, レーン戦と呼ばれるtop,midと呼ばれる2つのレーンで1on1を行う.
またbotというレーンでは火力が高いが体力が低いadcという役職のプレイヤーと火力は低いが回復やシールド能力のあるsupという役職が2on2で戦う.
jungleというレーンは中間モンスターと呼ばれる,相手プレイヤーとは直接関係のないモンスターを狩り経験値を高めつつ,味方のレーンを補助しにいったりする.
このとき,レーン戦ではチャンピオンによって対面が得意, 不得意がある.
あるチャンピオンに対して, そのチャンピオンに有利なチャンピオンをカウンターチャンプという.
例えばAnnieというチャンピオンはmidレーンにおいて火力は高いのだが, 射程はかなり短い. したがって射程の長いBrandやOriannna,Luxといったチャンプに弱い. 逆に射程の短いFizzやAkaliといったチャンプに対しては非常に有利である.
カウンターチャンプの概念はかなり重要でプロの試合でもチャンピオンピックの時点で有利不利が決まらないように工夫されている.
__________________________________________________

まずはJSONファイルの取得からする必要がある.
LoL Counter - Champions
今回はこのサイトからスクレイピングした.
(スクレイピングのやり方についてはいつか記載)
JSONファイルはここにおいてある.
champion1.json - Google ドライブ


赤線が不得意チャンプ, 青線が得意チャンプ, 緑線が味方で相性の良いチャンプ

import json
import matplotlib.pyplot as plt
import networkx as nx

def get_champion_relations_dict():
    """JSONファイルを取得
    """
    with open("champion.json","r") as f:
        return json.load(f)

def add_edges(Graph,champion_name,tmp_list,edge_color):
    """チャンピオンに対してtmp_listのチャンピオンに対するエッジを追加する
    """
    Graph.add_edges_from([(champion_name,champion) for champion in tmp_list],color=edge_color) 

if __name__ == "__main__":
    #有向グラフを宣言
    Graph = nx.DiGraph()

    #チャンピオンのJSONを取得
    champion_relations_dict = get_champion_relations_dict()
        
    #ノードを追加する
    Graph.add_nodes_from(list(champion_relations_dict.keys()))
    
    #カウンターチャンピオンに有向エッジを追加
    relations_dict = {"weak":"r","strong":"b","goes_well":"g"}
    for champion_name in champion_relations_dict.keys():#あるチャンピオンに対して
        for relation,color in relations_dict.items():#ある関係に対して
            opponent_list = champion_relations_dict[champion_name][relation][:3]
            add_edges(Graph,champion_name,opponent_list,color)
        
    
    #グラフの描画
    edges = Graph.edges()
    colors = [Graph[u][v]["color"] for u,v in edges]
    plt.figure(figsize=(50,50))
    pos = nx.spring_layout(Graph)
    labels=nx.draw_networkx_labels(Graph,pos=nx.spring_layout(Graph))
    nx.draw_networkx(Graph,pos,edge_color=colors,node_color="w",alpha=0.5,edge_labels=labels,font_size=9)
    plt.axis("off")
    plt.savefig("default.png")
    plt.show()

結果はいろいろ調整して以下のようになった.
f:id:umashika5555:20170822044629p:plain
f:id:umashika5555:20170822044635p:plain
f:id:umashika5555:20170822052216p:plain
f:id:umashika5555:20170822044641p:plain
正直, かなり見づらいしノードが多いため目的のチャンプを探すのに時間がかかる.
またノードの◯が表示されない場所があるのはライブラリの関係なのだろうか?
あと, グラフのノードの散乱をpos = nx.spring_layout(Graph,k=0.7)のように反発係数でやる以外に方法はないのか?
凡例の表示をどうするか?などの問題を解決していけたらよい.
これらを直せたら直していきたい.


【参考にしたサイト】
本家
https://networkx.github.io/documentation/networkx-1.9/examples/drawing/labels_and_colors.html
https://networkx.github.io/documentation/networkx-1.10/reference/functions.html
stack overflow
https://stackoverflow.com/questions/25639169/networkx-change-color-width-according-to-edge-attributes-inconsistent-result
https://stackoverflow.com/questions/24873626/python-networkx-adding-color-for-a-particular-edge
https://stackoverflow.com/questions/22992009/legend-in-python-networkx
Qiita
http://qiita.com/hitsumabushi845/items/270d81c5c8017014df95
http://qiita.com/inoory/items/088f719f2fd9a2ea4ee5
http://qiita.com/hatchinee/items/a904c1f8d732a4686c9d
Python辞書について
http://www.yukun.info/blog/2008/06/python-dict2.html

DeepLearning実装 #1

名著『ゼロから作るDeepLearning』を読み終わったので特に重要であった4,5,6,7章について4回に渡って解説をしたいと思う.
第1回目は4章の「ニューラルネットワークの学習」である.

4.1 データから学習する

ニューラルネットワークは他の機械学習の手法と違ってデータから学習できるというのが特徴.
すなわち重みパラメータの値をデータから自動で決定できる.
例えば手書き文字の認識を行いたいとき機械学習は人間が決めた「角がいくつあるか?」「横線がいくつあるか?」などの特徴量を抽出する.
しかしニューラルネットワークではその過程を自動でやってくれるため, 手書き文字の画像を突っ込めばよいだけである.

4.2 損失関数

2乗和誤差や交差エントロピー誤差がよく用いられる.
交差エントロピー誤差とは E = -\sum_{k}t_{k}\log{y_{k}} で表されます.
ここで t_{k} はone-hot-vectorなのでEは実質的に正解ラベルのものの確率の対数にマイナスをつけたものである.
例えば正解ラベルが「2」のときt = numpy.array([0,0,1,0,0,0,0,0,0,0])となっており y_{2} = 0.6ならば
 E = -\log{0.6} = 0.51 となる.
f:id:umashika5555:20170626082644p:plain
上図は y = -log(x)のグラフである. xが1に近づくほど(入力手書き文字画像が「2」である確率が1に近づくと)損失が少ないということがわかる.

ここでミニバッチ学習を適用すると損失関数は「バッチすべてのデータにおける訓練データ1つあたりの損失」となるので損失関数の定義は
 E = -\frac{1}{N}\sum_{n}\sum_{k}t_{nk}\log{y_{nk}}となる.

ミニバッチをランダムに取り出すときのテクニックとしてランダムに選ぶ方法がある.

#0-60000未満の数字の中からランダムに10個の数字を選ぶ
np.random.choice(60000,10)

バッチに対応した交差エントロピー誤差の実装として
正解ラベルがone-hot-vectorの場合とargmax(one-hot-vector)の2つの場合が考えられる.
どちらでも対応出来るように処理を書くと下のようになる.

def cross_entropy_error(y, t):
    """損失関数:クロスエントロピー誤差"""
    if y.ndim == 1:
        t = t.reshape(1, t.size)
        y = y.reshape(1, y.size)
    # 教師データがone-hot-vectorの場合、正解ラベルのインデックスに変換
    if t.size == y.size:
        t = t.argmax(axis=1)
    batch_size = y.shape[0]
    return -np.sum(np.log(y[np.arange(batch_size), t])) / batch_size

4.3 数値微分

損失関数を小さくするために勾配の情報を用いる.
勾配を得るために数値微分が必要となる.
微分の定義は \frac{df(x)}{dx} = \lim_{h \to 0}\frac{f(x+h)-f(x)}{h}である.
Pythonで実装する際にこのhは十分に小さい値だからといって1e-50などを選択してはいけない.
なぜなら丸め誤差の影響で計算機上では0と同値であるからである.
数値微分の誤差を減らす工夫として(x+h)と(x-h)での関数fの差分を計算して
 \frac{df(x)}{dx} = \lim_{h \to 0}\frac{f(x+h)-f(x-h)}{2h}より

def numeric_diff(f,x):
    h = 1e-4
    return (f(x+h)-f(x-h))/(2*h)

次に勾配法について説明する.
各地点において関数の値を最も減らす方向を示すのが勾配.
勾配が指す先は関数が小さくなる方向ではあるが関数の最小値とは限らないのが注意.
入力が x_{0},x_{1}とすると勾配法は
 x_{0} = x_{0}-\eta\frac{\partial f}{\partial x_{0}}
 x_{1} = x_{1}-\eta\frac{\partial f}{\partial x_{1}}
 \etaは学習率
関数の勾配がわかったところでニューラルネットワークに適用する.
すなわち行列式における勾配を求める.
ニューラルネットワークの重みをWとすると
\begin{equation}W= \begin{pmatrix}w_{11} &w_{12}\\ a_{21} &a_{22}\end{pmatrix}\end{equation}
ここで損失関数LをWで微分すると
\begin{equation}\frac{\partial L}{\partial W} = \begin{pmatrix}\frac{\partial L}{\partial w_{11}} &\frac{\partial L}{\partial w_{12}}\\ \frac{\partial L}{\partial w_{21}} &\frac{\partial L}{\partial w_{22}}\end{pmatrix}\end{equation}
というように各要素でLを偏微分する.

数値微分を用いた2層ニューラルネットワークを実装する.

class TwoLayerNet:
    
    def __init__(self,input_size,hidden_size,output_size,weight_init_std=0.01):
        self.params = {}
        self.params["W1"] = weight_init_std * np.random.randn(input_size,hidden_size)
        self.params["b1"] = np.zeros(hidden_size)
        self.params["W2"] = weight_init_std*np.random.randn(hidden_size,output_size)
        self.params["b2"] = np.zeros(output_size)
        
    def predict(self,x):
        W1,W2 = self.params["W1"],self.params["W2"]
        b1,b2 = self.params["b1"],self.params["b2"]
        
        a1 = np.dot(x,W1) + b1
        z1 = sigmoid(a1)
        a2 = np.dot(z1,W2) + b2
        y = softmax(a2)
        
        return y
    
    #x:入力データ, t:教師データ
    def loss(self,x,t):
        y = self.predict(x)
        return cross_entropy_error(y,t)
    
    def accuracy(self,x,t):
        y = predict(x)
        y = np.argmax(y,axis=1)
        t = np.argmax(t,axis=1)
        
        accuracy = np.sum(y == t)/float(x.shape[0])
        
    def numerical_gradient(self,x,t):
        loss_W = lambda W:self.loss(x,t)
        grads = {}
        grads["W1"] = numerical_gradient(loss_W,self.params["W1"])
        grads["b1"] = numerical_gradient(loss_W,self.params["b1"])
        grads["W2"] = numerical_gradient(loss_W,self.params["W2"])
        grads["b2"] = numerical_gradient(loss_W,self.params["b2"])
        
        return grads

MNISTデータセットをダウンロードしてトレーニングする.

#MNISTのインストール

train_loss_list = []

iters_num = 10000
train_size = x_train.shape[0]
batch_size = 100
learning_rate = 0.1

network = TwoLayerNet(input_size=784,hidden_size=50,output_size=10)

for i in range(iters_num):
    #ミニバッチの取得
    batch_mask = np.random.choice(train_size,batch_size)
    x_batch = x_train[batch_mask]
    t_batch = t_train[batch_mask]
    
    #勾配の計算
    grad = network.numerical_radient(x_batch,t_batch)
    
    #パラメータの更新
    for key in ("W1","b1","W2","b2"):
        network.params[key] -= learning_rate*grad[key]
    
    #学習経過の記録
    loss = network.loss(x_batch,t_batch)
    train_loss_list.append(loss)

これにテストをして精度を見る.
精度に関しては次の章で改めて書くと思うので省略.

教師あり学習分類問題の決定境界の可視化

パーセプトロン,SVM,ロジスティック回帰,ランダムフォレストなど「決定境界を求める」という分類問題を解く際に下のような2次元グラフで決定境界を可視化できると嬉しい.
今回は決定境界を引くアルゴリズムをまとめた.
f:id:umashika5555:20170625062041p:plain

手順は以下の通りである.

  1. 学習モデルでサンプルを分類する.
  2. 2Dグラフの軸の範囲を決める
  3. 2Dグラフ上にグリッドポイントを作成する
  4. グリッドポイント全てに対して学習モデルを適用
  5. グリッポポイントの等高線のプロット


1. 学習モデルでサンプルを分類する
今回はIrisデータセットからガクの長さ, 花弁の長さを特徴量として用いる.
http://www.geocities.jp/umashika_ningen/blog1.html
現在下記のような状態(サンプルとそのラベルはわかっている.)
f:id:umashika5555:20170625064850p:plain
ここで学習モデルをサンプルに適用し, 決定境界を求める.
学習によって得られた境界線をy = WX + bと数式を得ることができる.


2. 2Dグラフの軸の範囲を決める
まずサンプルの中で最も大きい値と小さい値をみてそれにフィットするようなグラフの範囲を決める.
特徴量の変数がXとすると

x1_min , x1_max = X[:,0].min()-1, X[:,0].max()+1
x2_min , x2_max = X[:,1].min()-1, X[:,1].max()+1

というように最小値-1,最大値+1を軸の範囲にする.

3. 2Dグラフ上にグリッドポイントを作成する
グラフ上に格子点を打つ.

resolution = 0.02
xx1,xx2 = np.meshgrid(np.arange(x1_min,x1_max,resolution),np.arange(x2_min,x2_max,resolution))

4. グリッドポイント全てに学習モデルを適用
1.の時点で境界線は引けているわけなので各グリッドポイントに対して予測のみをすれば良い.

#classifierは学習したモデル
#各特徴量を1次元配列に変換して予測を実行
Z=classifier.predict(np.array([xx1.ravel(),xx2.ravel()]).T)

5. グリッポポイントの等高線のプロット
決定境界をプロットする.

form matplotlib.pyplot as plt
#予測結果を元のグリッドポイントのデータサイズに変換
Z=Z.reshape(xx1.shape)
#グリッドポイントの等高線のプロット
plt.contourf(xx1,xx2,Z,alpha=0.4)

ベイズの定理

条件付き確率

f:id:umashika5555:20170617013313p:plain
事前確率P(A)についてBという事象が起こるという情報が与えられたときにAという事象が起こる確率を求めたい.
AとBの同時確率を事前確率で割る.
イメージとしてはこんな感じ.
オレンジの確率を赤の確率で割る.
f:id:umashika5555:20170617010946p:plain

ベイズの定理

結果がわかっているときに原因を推定する手法.

f:id:umashika5555:20170617012100p:plain
f:id:umashika5555:20170617012817p:plain
これを一般に拡張すると
f:id:umashika5555:20170617013154p:plain

分類問題の手法

  • ロジスティック回帰
  • 決定木
  • ランダムフォレスト

www.slideshare.net

apacheの設定

index.htmlは自分の環境だと/var/www/html/index.html



d.hatena.ne.jp

UbuntuにVirtualBoxを入れる

Ubuntu で Virtualbox を使う
Linux_Downloads – Oracle VM VirtualBox

【GitHub】ファイル名変更

ローカルリポジトリで名前を変更する

$git mv a.txt b.txt

ローカルリポジトリにコミット

$git commmit -m "名前変更したぞ"

リモートリポジトリに反映

$git push origin master

Gitよくわかってないので間違ってるかも