鴨川η

daftでグラフィカルモデル

はじめに

graphvizでは,上付き文字・下付き文字が表現できなかったので,daftを使ってみた.

とりあえず,topic modelsとpolylingual topic modelsのグラフィカルモデルを描いてみる.

daftの特徴

  • 土台となるオブジェクトがgridになっていて,そこの座標を指定してノードやプレートを追加していく
  • graphvizのようによしなに位置を決めて描画してくれない
  • python

環境

  • OS:MacOSX yosemite

必須

  • daft
  • matplotlib

options

  • jupyter

本題

daftの導入

pip install daft

LDAのグラフィカルモデル

from matplotlib import rc
%matplotlib inline
import daft

rc("font", family="Ricty", size=15)
rc("text", usetex=True)


pgm = daft.PGM(shape=[5, 5])

# Nodes
pgm.add_node(daft.Node("alpha", r"$\alpha$", 2, 4)) # 名前,ラベル,座標
pgm.add_node(daft.Node("theta", r"$\theta$", 2, 3))
pgm.add_node(daft.Node("z", r"$z_i$", 2, 2))
pgm.add_node(daft.Node("w", r"$w_i$", 2, 1, observed=True))

pgm.add_node(daft.Node("beta", r"$\beta$", 3, 3))
pgm.add_node(daft.Node("phi", r"$\phi$", 3, 2))


# Edges
pgm.add_edge("alpha", "theta")
pgm.add_edge("theta", "z")
pgm.add_edge("z", "w")
pgm.add_edge("beta", "phi")
pgm.add_edge("phi", "w")


# plate
pgm.add_plate(daft.Plate([1.5, 0.2, 1.1, 3.2], label=r"D",
    shift=-0.1))
pgm.add_plate(daft.Plate([1.6, 0.5, 0.9, 2], label=r"N",
    shift=-0.1))
pgm.add_plate(daft.Plate([2.7, 1.5, 0.7, 0.8], label=r"K",
    shift=-0.1))

pgm.render()
pgm.figure.savefig("lda.pdf")

これをjupyterで実行すると以下の図が描画される.

index.png

出てきた要素を順を追って説明していく.

土台

daft.PGMにノードやエッジを追加.

pgm = daft.PGM(shape=[5, 5]) であれば5*5のgridを用意する.

ノード

1つ1つノード作って,PGMオブジェクトに追加.

例えば, daft.Node("beta", r"$\beta$", 3, 3) であれば座標(3,3)にbetaという名前でr"$\beta$"というラベルをもつノードを生成. ここでつけた名前はエッジを作るときに使う.

座標の注意としては

  • (0,0)は左下
  • floatも指定可能

エッジ

例えば pgm.add_edge("z", "w") ならNodeオブジェクトのzからwへの有向辺を描画.

プレート

最後はPlateです(図の四角形のやつ). Nodeオブジェクトと同様にPlateオブジェクトを作ってPGMオブジェクトに追加.

pgm.add_plate(daft.Plate([1.5, 0.2, 1.1, 3.2], label=r"D", shift=-0.1)) を例にあげると,

最初のリストは,[Plateの左下のx座標, Plateの左下のy座標, 横幅, 縦幅] を指定. shift=-0.1は指定した値の分だけ,Plateの底の部分を移動. -0.1であれば下のほうに近づくし1とかにすればその分上にいく.

polylingual topic models

from matplotlib import rc
%matplotlib inline
import daft

rc("font", family="Ricty", size=15)
rc("text", usetex=True)


pgm = daft.PGM(shape=[7, 5])



# n.va = "baseline"
pgm.add_node(daft.Node("alpha", r"$\alpha$", 1, 2)) # 名前,ラベル,座標
pgm.add_node(daft.Node("theta", r"$\theta$", 2, 2))
pgm.add_node(daft.Node("z1", r"$z_i^{1}$", 3, 2.5))
pgm.add_node(daft.Node("z2", r"$z_i^{2}$", 3, 1.5))
pgm.add_node(daft.Node("w1", r"$w_i^{1}$", 4, 2.5, observed=True))
pgm.add_node(daft.Node("w2", r"$w_i^{2}$", 4, 1.5, observed=True))

pgm.add_node(daft.Node("beta1", r"$\beta^{1}$", 6, 2.5))
pgm.add_node(daft.Node("beta2", r"$\beta^{2}$", 6, 1.5))
pgm.add_node(daft.Node("phi1", r"$\phi^{1}$", 5, 2.5))
pgm.add_node(daft.Node("phi2", r"$\phi^{2}$", 5, 1.5))


# Edges.
pgm.add_edge("alpha", "theta")
pgm.add_edge("theta", "z1")
pgm.add_edge("z1", "w1")
pgm.add_edge("beta1", "phi1")
pgm.add_edge("phi1", "w1")
pgm.add_edge("theta", "z2")
pgm.add_edge("z2", "w2")
pgm.add_edge("beta2", "phi2")
pgm.add_edge("phi2", "w2")

# And a plate.
pgm.add_plate(daft.Plate([1.6, 1.0, 2.9, 2.0], label=r"$D$", shift=-0.1))

pgm.add_plate(daft.Plate([2.5, 1.1, 1.8, 0.8], label=r"$N_2$", shift=-0.1))

pgm.add_plate(daft.Plate([2.5, 2.1, 1.8, 0.8], label=r"$N_1$", shift=-0.1))

pgm.add_plate(daft.Plate([4.7, 1.0, 0.6, 2.0], label=r"$K$",
    shift=-0.1))

pgm.render()
pgm.figure.savefig("joint_lda.pdf")

index.png