Plate notation via Graphviz/RStudio

はじめに

いやー,ついに出ましたね,実戦ベイズモデリング
Amazonの書評にも投稿しちゃったけど,これプロの心理学者は全員目を通さないといけないんじゃないの。基礎実験でやってるようなことが全部ベイズモデリングされてるよ。少なくともこれからプロになる人は絶対読まないといけないんじゃないの。臨床家や実践家はなおさら。

もちろんこの本はぶっちぎってますからね,世界の最先端を垣間見せてくれるタイプのやつなので,「いくとこまで行ったらこんなこともできるのか!」とすごく動機付けられてから,青本緑本に戻って行ったらいいと思うんですけどね。

プレート表現

この本の特徴の一つが,モデルをプレート表現していること。プレート表現(plate notation)はモデルの図示にあたっての一つの表記法。怖い本で使われている表現方法で,「あー,そういうのもあるのか。そのうち勉強しないとなあ」と思っていましたが,今回この本でわかりやすく(たった2ページ!)にまとめてくれていました。これはありがたい。

これなら俺にも描けそうだ,と思ってちょっとやってみました。
というのも,以前からRStudioに標準装備のGraphvizをつかったダイアグラムの表現の仕方というのがあるのね。
詳しくはこの記事とかこの記事を見てもらえればいいかと思います。が,要するに最新版のRStudioを入れていたらもう入っているから,特に苦労しなくてももう使える環境があるってこと。あとはこのモデル図を書くdot記法とやらを習得すればいい。

RStudioが公式認定しているだけあって,ファイルの拡張子を.dotにするとdot記法の予約語はハイライトされるから,見よう見まねでいけそうなもんだ。

ということで,早速やってみました。まずは感銘を受けた付録の「プレート表現のルール」。これを次のようにして書いてみる。

library(DiagrammeR)
grViz("
Digraph rules{
  rankdir =TB;
  Cluster0 [shape=none,label=離散量か連続量か];
  離散 [shape=box]
  連続 [shape=circle]
  Cluster0 -> 離散,連続
  離散潜在 [shape=box]
  離散生成量 [shape=box,peripheries=2]
  離散顕在 [shape=box,style=filled]
  離散 -> 離散潜在,離散生成量,離散顕在;

  連続潜在 [shape=circle]
  連続生成量 [shape=doublecircle]
  連続顕在 [shape=circle,style=filled]
  連続 -> 連続潜在,連続生成量,連続顕在;
}
")

plot of chunk unnamed-chunk-1

ここではDiagrammeRパッケージを読み込んでgrViz関数でdot記法のソースコードを実行させたけど,実際はこのコードを「plateRule.dot」とでも名前をつけて(拡張子を.dotにして)保存したら,RStudioのpreviewボタンを押すだけでViewerの画面に図が出て来ます。コードハイライトもされているからバッチリ!やったね!

**ちょっと注意**
ここのソースコードではCluster0という明示されない(shape=none)ノードのラベルをダブルクォーテーションでくくる必要があります。この記事ではRコードからdotソースファイルを読むようにしたので,ソースのなかにダブルクォーテーションが入っているとそこでソースが途切れてエラーが出ます。

かける!かけるぞ!

なるほどこいつぁ簡単だ,と思っていくつかやってみました。あんまり綺麗じゃないけど,セクション18.1のモデルはこんな感じ。

grViz("
digraph sample18_1{
  rankdir = TB;
  newrank = true;
  subgraph cluster0{
    label =刺激ペアij;
    dij [shape=doublecircle];
    sij [shape=doublecircle];
  }
  subgraph cluster1{
    label=刺激i
    ri [shape=doublecircle];
    yi [shape=box,style=filled];
  }
  p [shape=circle,style=filled];
  w [shape=circle];
  c [shape=circle];
  γ [shape=circle,style=filled];
  b [shape=circle,style=filled];
  a [shape=box,style=filled];
  t [shape=box,style=filled];

  p -> dij;
  dij -> sij;
  w -> sij;
  c -> sij;
  γ -> ri;
  a -> ri;
  b -> ri;
  t -> yi;
  sij -> ri;
  ri -> yi;

  {rank = same; dij;p;}
  {rank = same; w; sij;}
  {rank = same; a;ri;b;}
  {rank=same;yi;t;}
}
")

plot of chunk unnamed-chunk-2

もうひとつ。セクション18.11の例。

grViz("
digraph sample1811{
  rankdir =TB;
  v [shape=circle];
  pi [shape=circle];
  {rank =same;v;pi;}

  subgraph cluster0
  {
    label=子供i
    zi [shape=box];
    subgraph cluster1
    {
      label=質問j
      pi_dash [shape=doublecircle];
      qij [shape=box,style=filled];
      gij [shape=box,style=filled];
    }
  }
  qij -> pi_dash;
  zi -> pi_dash;
  pi_dash -> gij;
  v -> pi_dash;
  pi -> pi_dash;
}
")

plot of chunk unnamed-chunk-3

うーん,ちょっと思ってるのと位置関係が違ったりするけど,まあなんとかなるかな?

すぐに壁が現れた

というとまあ簡単そうに見えますが,実はすぐに壁が現れたのです。上の例は,この壁の存在を理解してから描けそうなサンプルを選んだのね。

実はまず最初に書こうとしたのは,付録の図A.1なのです。一番簡単でわかりやすく表現されているから。ところがこれがうまくできない。反応の二値データは項目の特性と人の特性を分けて推定するので,それぞれにネストされているので,Graphvizでいうところのサブグラフがオーバーラップしているんですが,これが表現できない。

こうなっちゃう,

grViz("
Digraph figA1 {
  rankdir = LR;
  subgraph cluster0
  {
    label = person
    θ [shape=circle];
    p [shape=doublecircle];
    yij [shape=box,style=filled];
  }
  subgraph cluster1
  {
    label = Item
    b [shape=circle];
    subgraph cluster0{
      p [shape=doublecircle];
      yij [shape=box,style=filled];
    }
  }
  θ -> p;
  b -> p;
  p -> yij;
}
")

plot of chunk unnamed-chunk-4

アイテムの下にpとyijが入って来ないといけないのに,それができないんだなあ。どうにも。色々調べて見たんだけど,どうもそういう表現はできないようです(間違っていたら誰か教えて偉い人)。

Graphvizは複雑な構造とかネットワーク関係の表記にあるから,サブグラフがオーバーラップしているというのは設計思想に反するというか,考えられてないんじゃないかなと思ったり。でもプレート表現にはすごく必要なところなので(この図ではベイジアンモデリングの良さがまるで表現できてない!),ちょっと残念な感じです。

この記事ができるまで

この記事を作るにあたって参考にしたのは,次のサイト。

まあ必要そうなところを斜め読みしながら,サンプルコードを走らせながら,数時間でこの記事に描いてあるような図は描けたので,敷居は低いと言えそうですが,次のところが不満です。

  • TeX表記ができない。数式記号を「しーた」とか入れて変換するの超ダサい。下付き文字とかも書きたいし。
  • 上にも書いたけど階層構造のオーバーラップ
  • 位置の調整に細かい技が必要そう。考えなくても描いてくれるという良さでもあるんだけど。

これらの問題を解決しようとすると,今度はTeXで図を書くTikZの世界とかが出て来て,あーそこまで深入りしてらんねえ,ということで今日の自習時間は終わり。

余談だけど,もう一つの表現方法としての犬4匹本記法というのもあります。訳あって,個人的にはこっちの記法の方が慣れ親しんでる。分布の形もわかるからいいと思うんだ。

で,この記法については犬4匹本御本尊のこのサイトにあるように,TikZのソースコードの他にLibreOfficeのテンプレートがあるから,こっちのほうが導入のハードルが低いと思います。

私は当面は,ドロー系ソフトで行こうかな,と思ってます。直感的でわかりやすいからね。

ということで今日はここまで。

コメントは受け付けていません。