2018-09-04

Python で 主成分分析 をやってみた

今回は多変量解析手法の1つである 主成分分析を行います。

Principal Component Analysis の頭文字を取って PCA と呼ばれます。

主成分

主成分とは データのばらつきを表す ベクトルです。

射影したデータの分散が大きい順に 第一主成分、第二主成分 ... とよび、 最大でデータの次元数かデータ数(のいずれか小さい方)と同じ数の主成分を持ちます。

info
  • 次元数が主成分の最大となるのは 計算の過程で求める 共分散行列 のサイズが次元数となるからですが、 データ数によっても主成分が制限されるのは、データ数以上の主成分(直行するベクトル)は分散がほぼ0で意味のある値にならないためだそうです。 (@nishio さん から教えていただきました。もし誤解してたら訂正ください!)
  • 第一主成分の傾きは主成分(ベクトル)とデータの距離合計が最小になるような直線です。
    • このように言うと最小二乗法で求めた回帰直線とどう違うのかと思うんですが、 回帰直線の場合は Y方向の距離で、主成分の直線は直交方向の距離を最小にするようです。

それぞれの主成分がどの程度データの特徴を表しているかを 主成分負荷量 といい、その比率を 寄与率 といいます。

寄与率の小さな主成分を排除することを次元削減といい、これが主成分分析を行う大きなメリットです。

固有値

まずは仕組みを理解するためにライブラリを使わずに固有値・固有ベクトルから主成分を求め、描画してみます。

流れとしては以下のようになります

  • 分散共分散行列 を求める
  • 求めた分散共分散行列の固有値と固有ベクトルを求める
    • 主成分ベクトルは 列方向に 並ぶので、今回は転置してから使う

特異値分解することで共分散行列を用いずに求める方法もあるみたい ですが、それはまたの機会ということで。

scikit-learn

続いて、 scikit-learn の PCA クラスを使います。

pip でインストールできます

$ pip install scikit-learn
  • PCA のインスタンス作成時 n_components 引数に次元数を指定する
    • 今回は先程と同じ結果を求めたいので 次元数は 3 とする
  • 作成した PCA インスタンスに fit メソッドでデータを適用する
  • 求めるべき主成分ベクトルは components_ 属性に格納されている

これらの前提を踏まえ先程と同じグラフを描画します。

主成分得点

求めた主成分を新たな軸として、データの新たな座標を求めます。

主成分得点を求めるためには pca.transform メソッドを使います。

これは元データを主成分で一次変換しているのとほぼ同じです。

ほぼ というのは、transform では 0 (原点) がデータの中心になるので、 一次変換したデータから平均値をマイナスすることで同一の結果となりました。

今回は 第二主成分まで求めます。

画像の主成分分析

最後に画像の主成分を求めそれを描画してみます。

画像における寄与率の低い主成分を削除した(後に次元を戻した)らどのように描画されるのかを見てみます。

主成分の顔自体は地獄っぽいですが、変換されたデータはちゃんと描画されてます。

主成分を大きくするほど顔が鮮明になっていくのがわかりますね。 なんか白目気味なのは調整が必要なのかも。

最後にあまり関係のない画像も試してみましたが、主成分をすべて残しても元画像とは程遠い姿となりました。 主成分はこの画像の分散を考慮できていないのでうまく表せないんですね。

お疲れ様でした。間違い等あったら優しめに指摘ください。

参考