教師なし学習3　主成分分析

[Aidemy](https://aidemy.net/)　2020/10/29
#はじめに
　こんにちは、んがょぺです！バリバリの文系ですが、AIの可能性に興味を持ったのがきっかけで、AI特化型スクール「Aidemy」に通い、勉強しています。ここで得られた知識を皆さんと共有したいと思い、Qiitaでまとめています。以前のまとめ記事も多くの方に読んでいただけてとても嬉しいです。ありがとうございます！
　今回は、教師なし学習の3つ目の投稿になります。どうぞよろしくお願いします。

＊本記事は「Aidemy」での学習内容を「自分の言葉で」まとめたものになります。表現の間違いや勘違いを含む可能性があります。ご了承ください。

今回学ぶこと
・主成分分析について
・カーネル主成分分析について

#主成分分析
##主成分分析について
・__主成分分析__は、__少ないデータから元のデータを表すこと__、すなわちデータの要約（圧縮）を行う手法の一つである。
・主成分分析を行うと、__「全てのデータを効率よく説明できる軸（第一主成分軸）」__と__「それだけでは説明しきれないデータを効率よく説明できる軸（第二主成分軸）」__が作成される。
・__このうち第一主成分のみを使う__ことで、余分なデータを捨てられ、データが圧縮できる。
・主成分分析を使えば__次元削減__も行えるので、データを2、3次元に落として可視化させたり、回帰分析に使えるようにしたりできる。

##主成分分析の流れ（概要）
①データXを__標準化__する。
②特徴同士の__相関行列__を計算する。
③相関行列の__固有値と固有ベクトル__を求める。
④固有値の大きい方からk個（k＝圧縮したい次元数）選び、対応する固有ベクトルを選択する。
⑤選んだk個の固有ベクトルから__特徴変換行列W__を作成する。
⑥データXと行列Wの積を計算し、k次元に変換されたデータX'を得る。（終了）

##主成分分析①　標準化
・標準化とは、__データの各特徴を、平均を0分散を1になるように変換すること__である。
・標準化を行うことで、単位や基準の異なるデータを同じように扱えるようになる。

・標準化は以下のように行われる。　(データと平均の差)÷標準偏差
__X = (X - X.mean(axis=0))/X.std(axis=0)__

##主成分分析②　相関行列
・__相関行列__とは、各特徴データ同士の相関係数がk×k個集まった行列のことである。
__相関係数__は__2データ間の直線的な関係性の強さ__を表し、1に近いほど「aが正の一次関数の傾向が強い」すなわち、__正の相関__が強いと言え、-1に近いほど「aが負の一次関数の傾向が強い」すなわち、__負の相関__が強いと言える。
・相関係数が0に近いときは、直線的な傾向があまりないことを示す。

・相関行列Rの計算は以下のように行われる。
__R = np.corrcoef(X.T)__

・相関行列を行うnp.corrcoef()に渡すのが、転置を行ったデータ__X.T__であるのは、Xのまま渡すとデータそのもの（行同士）の相関行列を計算してしまうためである。今回は__「特徴データ（列同士）」の相関行列を計算したい__ので、このような場合は転置すれば良い。

##主成分分析③　固有値と固有ベクトル
・②で求めた相関行列Rは、__固有値分解__というものを行うと__固有値__と__固有ベクトル__に分解される。この二つはそれぞれ行列の次元数と同じ個数で分解される。
・固有ベクトルが示すのは、__行列Rにおいてその方向に情報が集中していること__、固有値は__その集中の度合い__を示す。

・固有値分解は以下のように取得できる。変数の__eigvals__に固有値が、__eigvecs__に固有ベクトルが昇順で格納される。
__eigvals, eigvecs = np.linalg.eigh(R)__

##主成分分析④⑤⑥　特徴変換
・ここでは、データの次元を任意のk次元に変換する手順を見ていく。
・③で分解した固有値のうち大きいものからk個を使って変換する（④）。具体的には、このk個の固有値にそれぞれ対応する固有ベクトルを連結して__特徴変換行列W__を作成する（⑤）。最後に、このWとデータXをかけることで、k次元に変換されたデータX'を取得することができる（⑥）。

・変換行列Wの作成方法は以下の通りである。(2次元に変換したい場合)
__W = np.c_[eigvecs[:,-1],eigvecs[:,-2]]__

・XとWの積は「行列積」なので__X.dot(W)__で計算する。

#主成分分析①〜⑥を簡単に行う
・以上①〜⑥の手順で主成分分析を行うことができるが、__PCA__というscikit-learnのクラスを使うことで簡単に主成分分析を行うことができる。

 ・コード![スクリーンショット 2020-10-29 12.26.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/9a9707d8-31fa-a2f8-47b6-2ffde6aee689.png)

・コードその2（3種類のワインデータを2次元にまとめる）![スクリーンショット 2020-10-29 12.29.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/4363f1c6-abbd-6a19-dd3f-25f58873b41c.png)

・結果![スクリーンショット 2020-10-29 12.30.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/8baa658a-b482-d492-1ebe-960dcf6b42da.png)

#回帰分析の前処理としての主成分分析
・LogisticRegression()を使用した回帰分析を実行する前に、主成分分析を行ってデータを圧縮しておくことで、より汎用性の高いモデルを作ることができる。

・以下では、データを分割したX_trainとX_testについて、標準化と主成分分析を行う。標準化には「StandardScaler」クラス、主成分分析にはPCAクラスを使うと良い。また、トレーニングデータとテストデータは共通の基準で処理する。
・trainデータは学習させる必要があるので「fit_transform()」を使い、testデータはそのまま「transform()」を使えば良い。

・コード![スクリーンショット 2020-10-29 12.36.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/041bc221-3f6e-1675-3ab2-5ee84508ee6e.png)


#カーネル主成分分析
##カーネル主成分分析とは
・回帰分析などの機械学習は線形分離を前提としているため、線形分離不可能な
データは扱うことができないが、非線形分離のデータを線形可能なデータに変換する__カーネル主成分分析（カーネルPCA）__という物を使えば、そのようなデータも扱うことができるようになる。
・カーネルPCAでは、与えられたN（データ数）×M（特徴）のデータを、新しい特徴M'を持ったN×M'のデータKに作り替えるということを行う。これを__カーネルトリック__と言い、Kを__カーネル行列__という。
・このカーネル行列Kは主成分分析をすることが可能となる。

##カーネルトリックについて
・カーネルトリックを行うには、まずカーネル行列Kを算出する必要がある。元のデータがN（データ数）×M（特徴）ならば、Kは__N×N__となる。
・カーネル行列は「データのペアごとの類似度」を計算した__カーネル関数__を行列にした物である。
・このカーネル関数は数種類あるが、今回はその中の動径基底関数（カーネル）の__ガウスカーネル__について見ていく。
・カーネル関数の一つガウスカーネルは以下のようにして計算できる。

```python
#データ同士の平方ユークリッド距離を計算
M = np.sum((X - X[:,np.newaxis])**2, axis=2)
#Mを使ってカーネル行列を計算
K = np.exp(-gamma*M)
```

##カーネルトリックしたデータを主成分分析
・先述の通り、カーネルトリックを行って取得したカーネル行列Kは、主成分分析を行うことができる。
・主成分分析を行うことで、元は線形分離不可能だったデータXを、線形分離可能なデータX'に変換することができる。

・コード![スクリーンショット 2020-10-29 12.38.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/06e6a936-b50b-98c2-d9e0-5c5c80514f44.png)

・結果![スクリーンショット 2020-10-29 12.38.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/698700/6d86ceb5-21ac-a9a8-aa8d-29176b572726.png)


##カーネル主成分分析を簡単に行う
・__KernelPCA__というscikit-learnのクラスを使うことで簡単にカーネル主成分分析を行うことができる。
・引数については、n_componentsが圧縮後の次元数、kernelが動径基底関数（カーネル）、gammaがカーネル行列の算出に使われる「γ」の値を示す。

```python
from sklearn.decomposition import KernelPCA
#KernelPCAインスタンスを作成し、主成分分析する
kpca = KernelPCA(n_components=2, kernel="rbf", gamma=15)
X_kpca = kpca.fit_transform(X)
```

#まとめ
・__主成分分析__によってデータの圧縮（__次元削減__）を行うことで、平面上に描画したり、回帰分析の精度を上げたりすることができる。
・主成分分析は、__PCAクラス__を呼び出すことで簡単に行える。
・動径基底関数（カーネル）によってデータを変換することで、線形分離不可能なデータに対して主成分分析を行うことができる。これによって、__線形分離不可能なデータが線形分離可能となり__、機械学習が可能になる。これを__カーネル主成分分析__という。
・カーネル主成分分析は__KernelPCAクラス__を呼び出すことで簡単に行える。

今回は以上です。最後まで読んでいただき、ありがとうございました。