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

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

Pythonで共分散を求めてみる

共分散とはなにか

共分散とは二組の対応するデータ同士の関係を表す統計的指標の一つです。




何に使えるのか

例えば、あるクラスの英語と数学の試験結果があるとします。

共分散の指標を用いる事で英語と数学の試験結果の関係を見ることが出来ます。

試験結果の関係とは一体どのようなものなのでしょうか。

簡単に言うと「英語の点数が高い人は数学の点数も高い」、「英語の点数が低い人は数学の点数も低い」みたいに片方の試験の結果に対するもう片方の試験結果の関係になります。

共分散の求め方

共分散を表す式は次のようになります。
 Cov(X,Y)= \frac{1}{N}\sum^{N}_{i=1}(x_{i} - \overline{x})(y_{i} - \overline{y})
ただしX,YはそれぞれN個のデータ\overline{x},\overline{y}はそれぞれの平均です。

この式について考えていきましょう。
 \sum^{N}_{i=1}はN個のX,Yのデータを1つづ処理を行い、その結果を和を求めています。
そして、 \frac{1}{N}と、その総和をデータ数(N)で割っています。これは平均を求めることでスケーリング処理を行っています。
(単純に総和を取るだけではデータ数が10、5000と増えていく毎に結果が大きくなってしまいますネ)

シグマの中身

次にシグマの中身を見てみます。一体何の総和を取っているのでしょうか。

シグマの中身は(x_{i}-\overline{x})(y_{i}-\overline{y})となっています。
x_{i},y_{i}はX,Yそれぞれのi番目のデータの組です。

試験結果を例にすると、学籍番号が若い順に1番目の数学と英語の試験結果の組み合わせ、2番目の数学と英語の試験結果の組み合わせ・・・
の様になります。

xとyの値に対し、それぞれ平均との差を取っています。このデータとデータ群の平均の差を偏差と呼びます。

つまり、(x_{i}-\overline{x})(y_{i}-\overline{y})はxとyの偏差を掛けあわせて居ることになりますね。

偏差を掛けあわせる事

xとyの偏差を掛け合わせると事は、どういうことを意味しているのでしょうか。
例として
Xを英語の試験結果(N人分)、Yを数学の試験結果(N人分)てみます。

X,Yから1番目のデータ(X_{1}, Y_{1})を取り出し、関係を考えてみましょう。


Xの点数が平均より高いYの点数が平均より高い
・・・ (x_{i}-\overline{x})(y_{i}-\overline{y}) → 正 × 正 = 正
Xの点数が平均より低いYの点数が平均より高い
・・・ (x_{i}-\overline{x})(y_{i}-\overline{y}) → 負 × 正 = 負
Xの点数が平均より高いYの点数が平均より低い
・・・ (x_{i}-\overline{x})(y_{i}-\overline{y}) → 正 × 負 = 負
Xの点数が平均より低いYの点数が平均より低い
・・・ (x_{i}-\overline{x})(y_{i}-\overline{y}) → 負 × 負 = 正

この様なパターンに分けられます。(まだまだパターンはありますが、簡単化の為にとりあえずこの4つを考えてみます)
XとYの偏差の積が正になるパターンはXとYの偏差の組み合わせが両方共正、もしくは負となる時ですね。
これは「英語の点数が低い人は数学の点数も低い」もしくは「英語の点数が高い人は数学の点数も高い」というパターンです。


逆にXとYの偏差の積が負になるパターンはXとYの偏差の組み合わせが(正、負)、もしくは(負、正)と互いに反対になる時です。
これは「英語の点数が低い人は数学の点数も高い」もしくは「英語の点数が高い人は数学の点数も低い」というパターンです。

偏差の総和を取る事

偏差の積の結果が正になるパターンと負になるパターンがあることが分かりました。

各学生に対して英語と数学の偏差の積の総和を取るとどうなるのでしょうか。

多くの学生が「英語の点数が高い人は数学の点数も高い」もしくは「英語の点数が低い人は数学の点数も低い」場合、
偏差の積は正を取る為、総和は大きくなります。


また、多くの学生が「英語の点数が高い人は数学の点数が低い」もしくは「英語の点数が低い人は数学の点数も低い」場合、
偏差の積は負を取る為、総和は負になります。


逆に偏差の積が正になる学生と負になる学生がまんべんなく存在する時、偏差の積が正になったり負になるので、総和を取ると打ち消し合い0に近づきます。

この様に、
Xが大きい時、Yも大きい傾向があると総和が大きくなり
Xが小さい時、Yが小さい傾向にあると総和がマイナスになり
XとYに関係が見られないと総和が0に近づきます。

コード

X = [50, 50, 80, 70, 90], Y = [50, 70, 60, 90, 100]の共分散を求めるpythonのプログラムは以下のようになります。
cov自体はlambda式を用いることで一行に収めることが出来ます。

X = [50, 50, 80, 70, 90]
Y = [50, 70, 60, 90, 100]
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))