読者です 読者をやめる 読者になる 読者になる

CUBE SUGAR CONTAINER

技術系のこと書きます。

Python: 相関行列を計算してヒートマップを描いてみる

Mac OS X Python matplotlib scikit-learn seaborn NumPy

以前、このブログで相関係数について解説した記事を書いたことがある。 相関係数というのは、データセットのある次元とある次元の関連性を示すものだった。

blog.amedama.jp

この相関係数を、データセットの各次元ごとに計算したものを相関行列と呼ぶ。 データ分析の世界では、それぞれの次元の関連性を見るときに、この相関行列を計算することがある。 また、それを見やすくするためにヒートマップというグラフを用いて図示することが多い。

今回は Python を使って相関行列を計算すると共にヒートマップを描いてみることにした。

使った環境は次の通り。

$ sw_vers 
ProductName:    Mac OS X
ProductVersion: 10.12.4
BuildVersion:   16E195
$ python --version
Python 3.5.3

下準備

今回は、相関行列の計算には NumPy を、グラフの描画には seaborn を使うのでインストールしておく。 最後の scikit-learn については、相関行列の計算に使うデータセットを読み込むためだけに使っている。

$ pip install seaborn numpy scikit-learn

相関行列を計算してみる

まずはヒートマップの描く以前に相関行列の計算から。 データセットにはみんな大好きアイリス (あやめ) データセットを用いる。 これは 150 行 4 次元の構造になっている。

>>> from sklearn import datasets
>>> dataset = datasets.load_iris()
>>> features = dataset.data
>>> features.shape
(150, 4)

相関行列の計算には NumPycorrcoef() 関数が使える。 この関数には、相関行列を計算したい次元をリストの形で渡す。 すごくベタに書くとしたら、こんな感じ。

>>> import numpy as np
>>> np.corrcoef([features[:, 0], features[:, 1], features[:, 2], features[:, 3]])
array([[ 1.        , -0.10936925,  0.87175416,  0.81795363],
       [-0.10936925,  1.        , -0.4205161 , -0.35654409],
       [ 0.87175416, -0.4205161 ,  1.        ,  0.9627571 ],
       [ 0.81795363, -0.35654409,  0.9627571 ,  1.        ]])

上記には、それぞれの次元ごとの相関係数が格納されている。 対角要素が全て 1 になっているのは、全く同じデータ同士の相関係数は 1 になるため。

ただ、実際には上記のようなベタ書きをする必要はない。 次元ごとにリストで、というのはようするに行と列を入れ替えれば良いということ。 つまり M 行 N 列のデータなら N 行 M 列に直して渡すことになる。

これは NumPy 行列なら transpose() メソッドで実現できる。

>>> features.transpose().shape
(4, 150)

ようするに、こうなる。

>>> np.corrcoef(features.transpose())
array([[ 1.        , -0.10936925,  0.87175416,  0.81795363],
       [-0.10936925,  1.        , -0.4205161 , -0.35654409],
       [ 0.87175416, -0.4205161 ,  1.        ,  0.9627571 ],
       [ 0.81795363, -0.35654409,  0.9627571 ,  1.        ]])

相関行列はこれで計算できた。

ヒートマップを描いてみる

続いては、先ほどの相関行列をヒートマップにしてみよう。 Python のグラフ描画ライブラリの seaborn には、あらかじめヒートマップを描くための API が用意されている。

次のサンプルコードではアイリスデータセットの相関行列をヒートマップで図示している。 それぞれの行の説明についてはコメントで補足している。

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

import numpy as np
from matplotlib import pyplot as plt
import seaborn as sns
from sklearn import datasets


def main():
    # アイリスデータセットを読み込む
    dataset = datasets.load_iris()

    features = dataset.data
    feature_names = dataset.feature_names

    # N 行 M 列を M 行 N 列に変換して相関行列を計算する
    correlation_matrix = np.corrcoef(features.transpose())

    # 相関行列のヒートマップを描く
    sns.heatmap(correlation_matrix, annot=True,
                xticklabels=feature_names,
                yticklabels=feature_names)

    # グラフを表示する
    plt.show()


if __name__ == '__main__':
    main()

上記を実行すると、次のようなグラフが得られる。

f:id:momijiame:20170418225256p:plain

このヒートマップでは、正の相関が強いものほど赤く、負の相関が強いものほど青く図示されている。 相関がないものについては色が薄いことから白に近づくことになる。 上記を見ると、アイリスデータセットには相関の強い次元が多いことが分かる。

主成分分析した結果の相関行列でヒートマップを描いてみる

ここで一つ気になったことを試してみることにした。 主成分分析した結果を相関行列にしてヒートマップで描いてみる、というものだ。 主成分分析とは何ぞや、ということは以下のブログエントリで書いた。

blog.amedama.jp

理屈の上では、主成分分析した結果は互いに直交した次元になるため相関しないはず。 これを相関行列とヒートマップで確かめてみよう、ということ。

次のサンプルコードでは、アイリスデータセットを主成分分析している。 そして、分析した内容に対して相関行列を計算してヒートマップを描いた。

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

import numpy as np
from matplotlib import pyplot as plt
import seaborn as sns
from sklearn import datasets
from sklearn.decomposition import PCA


def main():
    # アイリスデータセットを読み込む
    dataset = datasets.load_iris()

    features = dataset.data

    # 特徴量を主成分分析する
    pca = PCA()
    pca.fit(features)

    # 分析にもとづいて特徴量を主成分に変換する
    transformed_features = pca.fit_transform(features)

    # 主成分の相関行列を計算する
    correlation_matrix = np.corrcoef(transformed_features.transpose())

    # 主成分の相関行列をヒートマップで描く
    feature_names = ['PCA{0}'.format(i)
                     for i in range(features.shape[1])]
    sns.heatmap(correlation_matrix, annot=True,
                xticklabels=feature_names,
                yticklabels=feature_names)

    # グラフを表示する
    plt.show()


if __name__ == '__main__':
    main()

上記を実行すると、次のようなグラフが得られる。

f:id:momijiame:20170418225930p:plain

見事に真っ白で、互いに相関が全然ないことが分かる。 理屈通りの結果になった。

まとめ

  • 二つの次元の関連性を調べるには相関係数を用いる
  • データセットに含まれる全ての次元で相関係数を計算したものを相関行列と呼ぶ
  • 相関行列はヒートマップというグラフで図示することが多い
  • 主成分分析した結果の相関行列は対角要素を覗いてゼロになる

めでたしめでたし。