CUBE SUGAR CONTAINER

技術系のこと書きます。

統計: 共分散と相関係数でデータセットの相関を調べる

まず、二次元の特徴量をもったデータセットがあるときを考えてみよう。

もし、一方の次元の値が高いときに、もう一方も高い傾向があるときは、両者に正の相関があるという。 反対に、一方の次元の値が高いときに、もう一方は低い傾向があるときは、両者に負の相関があるという。

では、それぞれの次元に正または負の相関があるか否かを調べるには、具体的にどうしたら良いのだろうか。

散布図を描いてみる

それにはまず、散布図を描いてみるという選択肢がある。 x 軸と y 軸に、それぞれの次元の値をプロットするやり方だ。

このとき、例えば正の相関があるなら、値は次のように左下から右上にかけてプロットされる。

f:id:momijiame:20160924161630p:plain

これはつまり x 軸の次元の値が高いときに y 軸の次元の値も高くなることを示す。

反対に、負の相関があるなら、値は次のように左上から右下にかけてプロットされる。

f:id:momijiame:20160924161639p:plain

これはつまり x 軸の次元の値が高いときに y 軸の次元の値は低くなることを示す。

共分散・相関係数という統計量

ただ、散布図を描いただけでは、具体的にどれくらいの相関があるのかが分からない。 そう、相関には強弱がある。

例えば、次のようなふたつの散布図がある。 相関の強弱でいえば、前者の方が後者よりも強い。

f:id:momijiame:20160924161630p:plain

上記の相関は、後者と比較すると強い。

f:id:momijiame:20160924161729p:plain

上記の相関は、前者と比較すると弱い。

では、相関の強弱は具体的にどのようにすれば分かるのだろうか。 それには、相関の強弱を表す統計量を計算することになる。 それが今回紹介する共分散や相関係数といったもの。

共分散

共分散というのは、各次元の値から平均値を引いたもの同士をかけ合わせた上で、総和を取ってデータの点数で割ったもの。 これは、一言で表せば各次元の偏差 (平均値を引いた値) の積 (かけ算した値) の平均値 (総和をデータ点数で割った値) を計算している。

数式で表すと、次のようになる。

{ \displaystyle
s_{xy} = \frac{1}{N} \sum_{i = 1}^{N} (x_i - \bar{x}) (y_i - \bar{y})
}

上記で \bar{x}\bar{y} は、各次元の平均値を表している。

この共分散という統計量は、正の相関が強いほど数値がプラスに大きくなる。 そして、反対に負の相関が強いほど数値はマイナスに大きくなる。 また、相関が弱ければ数値はゼロに近づく。

例えば、先ほどの散布図であれば、前者は共分散が 835 であるのに対し、後者は 820 だった。

なぜ、そうなるのか?

先ほど、共分散の性質として、正の相関が強いほど数値がプラスに大きく、負の相関が強いほど数値がマイナスに大きくなる、と説明した。 ここでは、「そういうものなんだ」と納得してしまうよりも、理屈から理解しておきたい。

そこで、まずは補助線と補足を入れた次の散布図を見てほしい。

f:id:momijiame:20160924162131p:plain

補助線は x 軸と y 軸の平均値を示している。

各次元の補助線にもとづいて、それぞれの点が意味するところを考えてみよう。 点が、もし x 軸の補助線よりも右側にあれば偏差はプラスとなり、そして左側にあればマイナスになることが分かる。 同様に、点がもし y 軸の補助線よりも上側にあれば偏差はプラスとなり、そして下側にあればマイナスになることが分かる。

先ほどの例で示した散布図では、補助線を引くと第一象限と第三象限に点が集まっていた。 それにもとづいて、各象限における偏差と偏差の積の関係を図示してみよう。

f:id:momijiame:20160924162313p:plain

第一象限においては各次元の偏差がプラスになるため、積はプラスになる。 同様に第三象限においては各次元の偏差がマイナスになるため、積はプラスになる。

上記のようなパターンでは偏差の積はほとんどがプラスになることから、その平均値もプラスになることが分かる。

同じように、第二象限と第四象限に点が集まっているパターンについても考えてみよう。

f:id:momijiame:20160924162442p:plain

先ほどの例から、既にだいたい分かると思うんだけど、このときは偏差の積がマイナスになる。 そのため、偏差の積の平均値を取ると、その値がマイナスになることが分かる。

では、値がまんべんなく分布しているパターンではどうなるか。

f:id:momijiame:20160924162529p:plain

このようなときは、偏差の積がプラスだったりマイナスだったりとまちまちになる。 そのため、平均値を計算するとゼロに近づくというわけ。

ということで、共分散を見れば相関が正なのか負なのか分かることが理解できた。

相関係数への拡張

じゃあ共分散さえ見ておけばいつでもオッケーかというと、そうはいかない。 なぜかというと、共分散はそれ単独では相関の強弱が分かりづらいし、異なるデータセットで比較ができない。 どういうことかというと、共分散は元々のデータセットの値の大小 (単位) に影響を受けてしまう。

例えば、カブトムシとクジラの体長と体高の共分散について考えてみよう。 それぞれの値は、カブトムシが数 cm オーダーだとしたら、クジラは数千 cm オーダーになる。 それぞれの偏差の積の平均値を考えると、値の大きさが全く異なるだろうことが分かる。

相関の強度を異なるデータセットで比べるには、まずは単位に依存しない無名数に変換しないといけない。 それが次に紹介する相関係数だ。 これは、共分散を、各次元の標準偏差の積で割ったもの。

数式で表すと次のようになる。

r = \frac{s_{xy}}{s_x s_y}

s_{xy} が共分散で、s_xs_y が各次元の標準偏差。

省略せずに書くと、こう。

{ \displaystyle
r = \frac
{
  \frac{1}{N} \sum_{i = 1}^{N} (x_i - \bar{x}) (y_i - \bar{y})}
{
  \sqrt{\frac{1}{N} \sum_{i = 1}^{N} (x_i - \bar{x}) {}^2}
  \sqrt{\frac{1}{N} \sum_{i = 1}^{N} (y_i - \bar{y}) {}^2}
}
}

分母となる各次元の標準偏差は、二乗して平方根を取ることで符号をすべてプラスにしている。 そのため、共分散と比べるとプラスとマイナスの値が互いに打ち消し合うことがない。 つまり、分母の標準偏差の積は共分散が取りうる最大値となることが分かる。 結果として、相関係数は相関の強弱が -1 から 1 の間で得られることになる。

例えば、共分散で相関の強弱を示したときに使った散布図で、同じように相関係数も計算してみよう。 まず、この散布図では相関係数が 0.9897 として得られた。

f:id:momijiame:20160924161630p:plain

続いて、こちらの場合には相関係数は 0.805 だった。

f:id:momijiame:20160924161729p:plain

相関の強弱が、共分散よりも分かりやすく得られている。

また、次のようにふたつの次元が完全に比例するときは、相関係数が 1.0 になる。

f:id:momijiame:20160924163017p:plain

共分散と相関係数の注意点

ただ、共分散や相関係数でふたつの次元の相関関係が分かるとはいえ、それだけに頼るのは避けた方が良い。

例えば、次の散布図を見てもらいたい。

f:id:momijiame:20160924163634p:plain

上記の散布図には、ふたつの次元に明らかな規則性が見て取れる。

では、上記の共分散と相関係数はどうなるだろうか? なんと、どちらもゼロになるのだ。

共分散と相関係数は、あくまでふたつの次元の間に線形な関係があるか否かしか見ることができない。 先ほどのように、人の目でみればあきらかな法則性があったとして、数値の上ではそれが分からない。 そのため、ふたつの次元の間に関係性を見いだそうとするときは、共分散や相関係数だけを確認して終わることは避ける必要がある。

まとめ

  • ふたつの次元の相関関係の強弱は、共分散や相関係数といった統計量を計算することで分かる
  • ただし、それで分かるのは線形な関係があるか否かだけなので、それだけを確認して終わることは避ける必要がある

おまけ

最初のグラフを描くのに使った Python のソースコードは次の通り。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from matplotlib import pyplot as plt

import numpy as np


def main():
    N = 100
    R = 10
    x = np.arange(N) + np.random.rand(N) * R - R // 2
    y = np.arange(N) + np.random.rand(N) * R - R // 2

    xmu, xsigma = x.mean(), x.std()
    ymu, ysigma = y.mean(), y.std()

    covariance = sum([(xi - xmu) * (yi - ymu) for xi, yi in zip(x, y)]) / N
    print('共分散:', covariance)
    correlation_coefficient = covariance / (xsigma * ysigma)
    print('相関係数:', correlation_coefficient)

    plt.scatter(x, y)

    plt.xlabel('x')
    plt.ylabel('y')

    plt.grid()
    plt.show()


if __name__ == '__main__':
    main()

依存ライブラリとして matplotlib を使っているので、実行する前にインストールする必要がある。

$ pip install matplotlib