Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

ポリコリック相関係数

ポリコリック相関係数(polychoric correlation coefficient, 多分相関係数 とも)は順序尺度の変数同士での相関関係を測る係数。

推定方法

小杉考司(2013)を参考に、二段階の最尤推定を行う方法を紹介する。

まず、観測された順序尺度の変数の背景に連続尺度の変数が存在し、それらは二変量の標準正規分布に従うと仮定する。 2変量正規分布の空間を閾値で区切って離散化されたものが観測値として実現したと考える。

尤度関数

クロス集計表におけるセル(i,j)(i, j)の観測度数をnijn_{ij}とする(i=1,2,⋯ ,s, j=1,2,⋯ ,ri=1,2,\cdots, s, \ j=1,2,\cdots,r)。

観測度数がセル(i,j)(i, j)に含まれる確率をπij\pi_{ij}とすれば、そのサンプルの尤度は

L=C∏i=1s∏j=1rπijnijL = C \prod^s_{i=1} \prod^r_{j=1} \pi_{ij}^{n_{ij}}

である。ここでCCは定数で、最尤推定においては推定に関わらないので気にしなくてよい。対数尤度は

ℓ=ln⁡L=ln⁡C+∑i=1s∑j=1rnijln⁡πij\ell = \ln L = \ln C + \sum^s_{i=1} \sum^r_{j=1} n_{ij} \ln \pi_{ij}

相関を測りたい変数がx,yx,yの2つあるとし、変数xxの閾値をaia_i、変数yyの閾値をbjb_jと表す(i=0,1,2,⋯ ,s, j=0,1,2,⋯ ,ri=0, 1,2,\cdots, s, \ j=0,1,2,\cdots,r)。 ここでa0=b0=−∞,as=br=+∞a_0 = b_0 = -\infty, a_s = b_r = +\inftyである。

πij\pi_{ij}は相関係数ρ\rhoの2変数正規分布Φ2\Phi_2を用いて

πij=Φ2(ai,bj)−Φ2(ai−1,bj)−Φ2(ai,bj−1)+Φ2(ai−1,bj−1)\pi_{ij} = \Phi_2(a_i, b_j) - \Phi_2(a_{i-1}, b_j) - \Phi_2(a_i, b_{j-1}) + \Phi_2(a_{i-1}, b_{j-1})

と表すことができる。

推定

閾値は次のように推定することができる。

ai=Φ1−1(Pi⋅)bj=Φ1−1(P⋅j)\begin{aligned} a_i = \Phi_1^{-1}(P_{i \cdot})\\ b_j = \Phi_1^{-1}(P_{\cdot j}) \end{aligned}

ここでPi⋅,P⋅jP_{i \cdot}, P_{\cdot j}は観測された累積周辺分布である。

Source
/tmp/ipykernel_1198361/2892077882.py:31: UserWarning: FigureCanvasAgg is non-interactive, and thus cannot be shown
  fig.show()
<Figure size 400x400 with 2 Axes>

推定の流れ

実際に推定してみよう。

次のようなデータがあるとする

Source
/tmp/ipykernel_1198361/2450860406.py:21: UserWarning: FigureCanvasAgg is non-interactive, and thus cannot be shown
  fig.show()
<Figure size 640x480 with 1 Axes>

まずクロス集計表を作って観測度数を得る。

Loading...

クロス集計表を横軸や縦軸に向けて合計していき、累積周辺分布Pi⋅,P⋅jP_{i \cdot}, P_{\cdot j}を得る

Pi=array([0.48, 1.  ]) Pj=array([0.08, 0.85, 1.  ])

ai,bja_i, b_jを推定する。a0=b0=−∞a_0 = b_0 = -\infty、as=br=∞a_s = b_r = \inftyとなるようにする

a=[-inf, np.float64(-0.05015358346473367), np.float64(inf)]
b=[-inf, np.float64(-1.4050715603096329), np.float64(1.0364333894937898), np.float64(inf)]

確率密度

πij=Φ2(ai,bj)−Φ2(ai−1,bj)−Φ2(ai,bj−1)+Φ2(ai−1,bj−1)\pi_{ij} = \Phi_2(a_i, b_j) - \Phi_2(a_{i-1}, b_j) - \Phi_2(a_i, b_{j-1}) + \Phi_2(a_{i-1}, b_{j-1})

の推定と、対数尤度

ln⁡L=ln⁡C+∑i=1s∑j=1rnijln⁡πij\ln L = \ln C + \sum^s_{i=1} \sum^r_{j=1} n_{ij} \ln \pi_{ij}

の計算を行う関数を作る

np.float64(-135.95432934194218)

尤度を最大にするρ\rhoを探索する。

今回はρ\rhoが(−1,1)(-1, 1)にあることがわかっているので、その範囲を細かく刻んで全部計算して最良のρ\rhoを推定値とする、という全探索法をつかうこともできる。

この方法を実際に行ったのが次の図である。

Source
/tmp/ipykernel_1198361/84596571.py:15: UserWarning: FigureCanvasAgg is non-interactive, and thus cannot be shown
  fig.show()
<Figure size 640x480 with 1 Axes>

scipy.optimize.fminboundなどを使ってBrent法という最適化手法を用いると効率的である。

(実際、semopyやRyStatsなどのパッケージではscipyの最適化関数を呼び出すことでBrent法を使っている: semopy/polycorr.py)

np.float64(0.5697450392307374)

ポリコリック相関係数の考え方まとめ

2つの順序尺度変数 X,YX, Y があるとし、それぞれ次のように閾値で切って離散化されたと仮定する

X=i if τX,i−1<X∗≤τX,iY=j if τY,j−1<Y∗≤τY,j\begin{array}{lll} X=i & \text { if } & \tau_{X, i-1}<X^* \leq \tau_{X, i} \\ Y=j & \text { if } & \tau_{Y, j-1}<Y^* \leq \tau_{Y, j} \end{array}

ここで

  • X∗,Y∗X^*, Y^* :潜在的な連続変数

  • τX,i,τY,j\tau_{X, i}, \tau_{Y, j} :それぞれのカデコリに対応するしきい値

  • (X∗,Y∗)∼N2(0,0,1,1,ρ)\left(X^*, Y^*\right) \sim N_2(0,0,1,1, \rho) :平均0、分散 1、相関 ρ\rho の2変量正規分布に従うと仮定

である。

X,YX, Yのクロス集計を考えると、観測セル(i,j)(i,j)の確率は、2変量正規分布の累積分布Φ2\Phi_2で表される

Pij=Pr⁡(X=i,Y=j)=Φ2(τX,i,τY,j;ρ)−Φ2(τX,i−1,τY,j;ρ)−Φ2(τX,i,τY,j−1;ρ)+Φ2(τX,i−1,τY,j−1;ρ)P_{i j} = \operatorname{Pr}(X=i, Y=j) = \Phi_2\left(\tau_{X, i}, \tau_{Y, j} ; \rho\right) -\Phi_2\left(\tau_{X, i-1}, \tau_{Y, j} ; \rho\right) -\Phi_2\left(\tau_{X, i}, \tau_{Y, j-1} ; \rho\right) +\Phi_2\left(\tau_{X, i-1}, \tau_{Y, j-1} ; \rho\right)

ここで Φ2(a,b;ρ)\Phi_2(a, b; \rho) は 平均0・分散1・相関 ρ\rho の2変量正規分布の累積分布関数(CDF)である。

観測されたクロス集計表 {nij}\left\{n_{i j}\right\} に基づく尤度関数は

log⁡L(ρ,{τX},{τY})=∑i∑jnij⋅log⁡(Pij)\log L\left(\rho,\left\{\tau_X\right\},\left\{\tau_Y\right\}\right) = \sum_i \sum_j n_{i j} \cdot \log \left(P_{i j}\right)

となる。ここで

  • nijn_{i j} :カテゴリ (i,j)(i, j) の観測頻度

  • PijP_{i j} :上記の矩形積分によって計算される理論確率

である。

PijP_{ij}を計算するときに使う閾値τX,τY\tau_X, \tau_Yは単変量の正規分布の累積分布関数Φ1(⋅)\Phi_1(\cdot)を使って次のように推定することができる。

τX=Φ1−1(Pi⋅)τY=Φ1−1(P⋅j)\begin{aligned} \tau_X = \Phi_1^{-1}(P_{i \cdot})\\ \tau_Y = \Phi_1^{-1}(P_{\cdot j}) \end{aligned}

ここでPi⋅,P⋅jP_{i \cdot}, P_{\cdot j}は観測された累積周辺分布である。

τX,τY\tau_X, \tau_Yを観測値から推定することで、最尤推定する対象はρ\rhoだけになる

ρ^=argmax⁡ρlog⁡L(ρ)\hat{\rho} = \operatorname*{arg max}_{\rho} \log L (\rho)
関連文献

閾値の推定のとき下限と上限を無限以外の計算可能な値にすると対数尤度関数が不連続なジャンプをしにくい

/tmp/ipykernel_1198361/3882806428.py:118: UserWarning: FigureCanvasAgg is non-interactive, and thus cannot be shown
  fig.show()
np.float64(0.5697450392307374)
<Figure size 400x300 with 1 Axes>
/tmp/ipykernel_1198361/3882806428.py:118: UserWarning: FigureCanvasAgg is non-interactive, and thus cannot be shown
  fig.show()
np.float64(0.5697450392307374)
<Figure size 400x300 with 1 Axes>

メモ:実装の高速化

問題:CDF計算

素朴に実装した場合の問題点

ρ\rho の評価のたびに、セルごとに scipy.stats.multivariate_normal の frozen オブジェクトを作り、Φ2\Phi_2 を4回呼んでいる

multivariate_normal.cdf は内部で数値積分を行うため、1点あたりの計算量が多く、結果に微小な誤差(揺らぎ)も入る。

74.8 μs ± 658 ns per loop (mean ± std. dev. of 3 runs, 10,000 loops each)

Owen の T 関数による閉形式

Owen の T 関数 T(h,a)T(h, a) (Owen, 1956)を使うと、2変量標準正規分布のCDFは、閉形式で厳密に書ける

Φ2(h,k;ρ)=Φ(h)+Φ(k)2−T(h,ah)−T(k,ak)−δ\Phi_2(h, k; \rho) = \frac{\Phi(h) + \Phi(k)}{2} - T(h, a_h) - T(k, a_k) - \delta
ah=k−ρhh1−ρ2,ak=h−ρkk1−ρ2,δ={12hk<0 または (hk=0 かつ h+k<0)0それ以外a_h = \frac{k - \rho h}{h\sqrt{1-\rho^2}}, \quad a_k = \frac{h - \rho k}{k\sqrt{1-\rho^2}}, \quad \delta = \begin{cases} \tfrac12 & hk < 0 \text{ または } (hk=0 \text{ かつ } h+k<0) \\ 0 & \text{それ以外} \end{cases}

T(h,a)T(h, a) は scipy.special.owens_t として提供されており、ベクトル化済みのC実装

最大誤差: 2.22e-16

速度比較

2.46 ms ± 4.86 μs per loop (mean ± std. dev. of 3 runs, 100 loops each)
109 μs ± 756 ns per loop (mean ± std. dev. of 3 runs, 10,000 loops each)