概要
マルコフチェーン(markov chain)を、PythonのPydotplus(又はPydot)からGraphvizを使って簡単に作るモジュール(markovViz)を作成しました。以下イメージです。
入力条件
pandasのデータフレームのindexを遷移元、columnを遷移先とし、値として遷移確率を設けたデータフレームを入力とします。
以下がイメージです。
表の値の説明(抜粋)
- 状態aからbに遷移する確率:20%
- 状態aからdに遷移する確率: 0%
- 状態bからaに遷移する確率:70%
- 状態bから遷移しない確率:30%
プログラム
以下がソースコードです。適当に張り付けて使ってください。
#必要なモジュールのインポート import pandas as pd import numpy as np import pydotplus def markovViz(markovdf, fileName='default.png'): #オブジェクトを定義 graph = pydotplus.Dot(graph_type='digraph') #ノードを追加 for c in df.columns: node = pydotplus.Node(c) graph.add_node(node) #エッジを追加 for i in df.index: for c in df.columns: if df.ix[i, c] > 0: edge = pydotplus.Edge(graph.get_node(i)[0], graph.get_node(c)[0]) edge.set_label('{:.1f}'.format(df.ix[i, c])) graph.add_edge(edge) #グラフ描画 graph.write_png(fileName, prog='dot')
いろいろ試してみる
せっかく作ったのでいろいろ試してみました。
まずは例題の結果。
if __name__ == "__main__": df = pd.DataFrame(index=['a', 'b', 'c', 'd'], columns=['a', 'b', 'c', 'd'], data=[[0.6, 0.2, 0.2, 0.0], [0.7, 0.3, 0.0, 0.0], [0.0, 0.4, 0.5, 0.1], [0.1, 0.3, 0.3, 0.3]]) markovViz(df)
ラベルと線の間の余白や線の曲がりがちょっと気になりますが、まずは使えるレベルと言えそうですね。
10の状態を設けた場合の結果。
if __name__ == "__main__": #ランダムなデータを作成 np.random.seed(0) data = np.random.rand(10, 10) #行方向の合計が1になるように正規化 data = (data / data.sum(axis=0)).T #DataFrame作成 df = pd.DataFrame(data, index=np.arange(10).astype('str'), columns=np.arange(10).astype('str')) #グラフ作成 markovViz(df)
うまくかけていますね。こういうのを見ると、Graphvizやるなぁ、という気がします。
20の状態を設けた場合の結果。
ここまでくると何が何だかわかりませんが、参考ということで。