元理系院生の新入社員がPythonとJavaで色々頑張るブログ

プログラミングや機械学習について調べた事を書いていきます

Pythonで相関係数を求めてみる

相関係数とはなにか

多変量の変数の関係性を示す指標の一つに共分散がありました。

相関係数は共分散の弱点を補ったものです。

今回はこの相関係数を求めるプログラムをPythonで記述してみます。

共分散の弱点

共分散は2組のデータの関係性を示す指標でした。


Pythonで共分散を求めてみる - 理系大学生がPythonで色々頑張るブログ

例としてあるクラスの英語と数学の試験結果のデータがあるとします。

数学の点数(点) 英語の点数(点)
81 91
88 96
13 14
48 43
58 73
29 20
86 71
81 88
78 65
79 87

この試験結果を横軸に数学、縦軸に英語の点数をとって図にしてみると次のようになります。
f:id:emoson:20141028173928j:plain

綺麗に右斜上に向かった図ですね。これは英語の点数が高い人は数学の点数も高く、英語の点数が低い人は数学の点数も低くなる傾向を表しています。


また、この試験結果に付いて共分散を求めてみると

X = [81,88,13,48,58,29,86,81,78,79]
Y = [91,96,14,43,73,20,71,88,65,87]
cov = lambda item1, item2: sum([(i[0]-sum(item1)/len(item1)) * (i[1]-sum(item2)/len(item2)) for i in zip(item1, item2)]) / len(item1)
print(cov(X,Y))

Cov(数学,英語) = 651.9199999..
なりました。

なんとなく強く関係してそうな感じですが、どの程度強いのかよく分かりませんね。

はっきりと強さがわからない所が共分散の弱点であり、この問題をスケーリング化する事で解決した手法が相関係数となります。

相関係数

共分散のおさらい

共分散の式を確認してみます。
 Cov(X,Y)= \frac{1}{N}\sum^{N}_{i=1}(x_{i} - \overline{x})(y_{i} - \overline{y})

この式はXとYの要素の偏差(平均との差)を掛けあわせて総和を取り、最後に平均にすることで求まります。

共分散の問題はXの偏差とYの偏差の単位(大きさ)を同じモノとして扱っている事が原因です。

なので、XとYの偏差の単位(大きさ)を揃えてあげることでこの問題を解決することが出来ます。

単位を合わせる

XとYそれぞれの偏差の単位を合わせる為に、それぞれの偏差をデータのバラつきで割ってみます。

式にすると次のようになります。

 \frac{x_{i}-\overline{x}}{xの標準偏差}

これを2変量に適応すると次のようになります
 R = \frac{1}{N} \sum^{N}_{i=1}\frac{(x_{i} - \overline{x})}{\sqrt{V(x)}} \times \frac{(y_{i} - \overline{y})}{\sqrt{V(y)}}

V(x)はxの分散

更にこれを式変形すると
 R = \frac{\frac{1}{N} \sum^{N}_{i=1}(x_{i} - \overline{x})(y_{i} - \overline{y})}{ \sqrt{\frac{1}{N}\sum^{N}_{i=1}(x_{i}-\overline{x})^{2}}\times \sqrt{\frac{1}{N}\sum^{N}_{i=1}(y_{i}-\overline{y})^{2}}}

この式のそれぞれの項をわかりやすくすると次のようになります。
 相関係数 = \frac{xとyの共分散}{xの標準偏差 \times yの標準偏差}

相関係数はそれぞれの偏差の項を-1から1にスケーリングを行っているので、相関係数も0から1に収まります。

Pythonで相関係数を求める

相関係数を求めるコードは次のようになります

var = lambda item: sum([(i-sum(item)/len(item))**2 for i in item]) / len(item)
cov = lambda item1, item2: sum([(i[0]-sum(item1)/len(item1)) * (i[1]-sum(item2)/len(item2)) for i in zip(item1, item2)]) / len(item1)
r = lambda item1, item2: cov(item1,item2) / (var(item1)**0.5*var(item2)**0.5)
X = [81,88,13,48,58,29,86,81,78,79]
Y = [91,96,14,43,73,20,71,88,65,87]
print(r(X,Y))

先ほどの英語と数学の点数のデータを与えると0.9356...となります。

強い相関を持っていることがはっきりと分かりますね。