Stanでpolychoric相関係数を推定する

 

この記事はStan Advent Calendar2017の5日目の記事です。

今回は,Stanでポリコリック相関係数を推定するという内容です。

ポリコリック相関係数とは

ポリコリック相関係数は,順序性があるカテゴリカルデータ同士の相関係数の一種です。順序性のあるカテゴリカル・データのための相関係数といえばスピアマンの順位相関とか,ケンドールの順位相関がありますが,ポリコリック相関係数はパラメトリックな方法なので確率モデルを定義して,ベイズ推定も可能です。

ポリコリック相関係数については以前書いた記事があるのでそちらを見てもらえると早いです。

簡単に言えば,順序データの背後に連続的な変数があると想定します。得られたデータは本来は連続的な値をとる性質をもつ変数なんだけど,データとしてはカテゴリカルになってしまった,とかそういう想定です。で,背後にある真の連続値同士の相関を推定しましょう,というのがポリコリック相関係数というわけです。

具体的には,心理尺度なんかが典型的です。心理尺度では態度を5段階評定で測定したりしますが,間隔が等しいという仮定が満たされない場合は順序尺度データとして扱わざるをえない時があります。そういうときにポリコリック相関係数を使うと,より妥当な相関関係を推定できると考えられています。

 

ポリコリック相関係数の確率モデル

ポリコリック相関係数は,背後に仮定される連続的な値が,推定したい相関係数を持つ二変量正規分布に従うと考えます。そして,それがカテゴリの閾値に従ってクロス表として実現するという想定です。なのでデータとして使うのもクロス表です。推定するのは,相関係数と閾値です。

このあたりの確率モデルについては,小杉先生の資料がとてもわかりやすくて参考になります。

確率モデルは,次のようになります。

ここで,i,jはクロス表の行列を表す添字で,nはクロス表における各セルの人数です。πはセルに所属する確率です。このπは,背後にある連続変量が二変量正規分布に従う場合,次のように計算できます。

ここで,Φ2()は二変量累積正規関数,α,βは変数1,変数2の閾値パラメータ,ρはポリコリック相関係数です。

確率モデルは以上で,あとはαとβに適当な無情報事前分布を,ρにlkj_corr()などで事前分布を仮定すればベイズ推定が可能です。

 

ただし・・・

実は,Stan2.17現在では,二変量累積正規関数はStanには入っていません。なので自分で定義しないといけないわけです。

いろいろ論文を調べると,二変量累積正規関数は,Owenのt関数を使って計算できるようです。この論文の式(4)がそれです。

幸いにも,StanにはOwenのt関数が最初から入ってるのでそれを使えば比較的簡単に実装できそうですね。

そして世の中にはすごい人がいろいろいるもんで,Stanの掲示板に二変量累積正規関数を作ってあげてくれている人がいました。いやーありがたい。

https://github.com/stan-dev/stan/issues/2356

ただ,このままだと推定上うまくいかないこともあたったので,ちょっと修正して使っています。

リンク先を見ると,将来的にはStanにも二変量累積正規関数が正式に実装されそうです。

 

ポリコリック相関係数を計算するためのコード

それでは早速ポリコリック相関係数を推定するためのStanコードを書いてみます。以下のようになります。これをpolychoric.stanというファイルに保存します。

 

今回使うパッケージは以下です。ここにまとめておきます。

 

これを,次のRで実行するコードは以下です。ちょっと長くなるので関数化しています。

 

コアは適宜環境に合わせて複数に変えてください。iterとwarmup,chainsも引数で変えられます。

Rコードを見てもらえればわかるように,閾値の初期値は累積正規関数(qnorm)で計算しています。

この関数の使い方は,次のような感じ。なお,データはpsychパッケージのbfiというデータセットから最初の2変数だけ取り出しています。

 

まずStanコードをコンパイルして,model.polyにいれます。一度コンパイルすればどんなデータでも同じモデルでできるので,サクサクです。

それとデータを引数にしてpolycorr.stan関数に入れます。戻り値はStanfitクラスのオブジェクトなので,いつものように結果の中身を見ます。相関係数はrho,閾値はthr1とthr2というパラメータ名で取り出せます。

推定時間は僕のPCで4000回のサンプリングで33秒ほどでした。データはクロス表を入れているので,実はサンプルサイズが大きくなってもほとんど推定時間は変わりません。逆に,カテゴリ数(つまりクロス表のセル数)が大きくなると推定時間が長くなります。

結果は以下です。

ちゃんと収束してそうです。

ついでに,psychパッケージにはポリコリック相関係数を出してくれるpolychoric()という関数があります。結果を比較すると,当たり前ですが一致します。

 

2step推定

さて,ポリコリック相関係数だけを知りたい場合は,閾値をデータから直接計算して,それを固定した上で相関だけを計算するということもできます。これを2step推定と呼んだりします。もちろん,すべてのパラメータを同時に推定した方がいいのですが,閾値と相関は互いにほとんど影響しあわないみたいで,2step推定でも分析精度はほとんどかわらず,むしろ推定の安定化・高速化ができます。

というわけで,2step推定をするためのStanコードを書いておきます。これをpolychoric_2step.stanというファイルに保存します。

 

これに対応した,関数を作りました。polycorr.stan1()です。

 

これを次のRコードで実行します。さっきとほとんど同じです。

 

今度は4000回のサンプリングで5秒弱になりました。結果はほぼ同じです。

 

ポリコリック相関行列を一気に推定したい

上のコードでは1つの相関係数しか推定できませんでした。しかし,実際は複数の項目間の相関を一気に推定したいことがほとんどです。

というわけで,ポリコリック相関行列を推定するためのStanコードを書いてみました。

これをpolychoric_multi.stanというファイルに保存します。

 

ポイントは,カテゴリ数が違う変数が入ってる場合にも対応するように,一番カテゴリ数が大きいものをSmaxという変数に入れて,それにあわせてベクトルの要素数などを定義しています。カテゴリ数が小さい変数の場合は適当な数字を入れておきます。実際には推定に使わないので数値であればなんでもいいです。

次に,相関行列を直接サンプリングするより,相関行列のコレスキー分解の要素を推定するほうが安定して,「正定値になってないよ!」,というエラーを防げます。初期値もピアソンの相関行列のコレスキー分解したものを入れます。

ほかにも多変量バージョンにするためにちょいちょい面倒なことやってますが,推定部分で言えばそんなに難しいことはしていません。

こちらも関数を用意しました。polycorr.stan2()です。好きなように名前は変えてください。

 

次のコードで実行します。

 

推定には4000回で125秒程度でした。相関係数の数が10個なので,個別に推定したほうが早いという結果が・・・(笑)。

結果は以下です。

 

対角行列は推定対象じゃないので,rhatは気にしなくていいです。それ以外が収束しているのはわかると思います。

事後分布を見てみます。

 

うまく収束しています。

次に,これを相関行列の形式で出力します。medianを使ってみました。

 

polychoric()の結果は以下です。最尤法の結果ときれいに一致しているのがわかると思います。

 

これだけキレイに一致するんなら最尤法でいいじゃないか,という気もしますが・・・ データによっては最尤法は不適解(-1~1の範囲を超える)が出たり,標準誤差がめちゃくちゃ大きくなったり不安定な結果になることもあります。MCMCだとそのあたりは安定して推定できるので,最尤法だとうまくいかないときの選択肢としていいかなと思います。

明日のStan Advent Calendarも僕ですが,今回のポリコリック相関行列を使ってカテゴリカル因子分析を実行する方法について書く予定です。

Enjoy!

 

関数をまとめたコード

 

 

 

 

This entry was posted in 心理統計学, Stan. Bookmark the permalink.