【初心者】特徴量エンジニアリング（次元低減）について調べてみた

# 背景・目的
私は、現在データエンジニアリングを生業としています。普段は、データ基盤の構築や、パフォーマンスチューニングなどビックデータに関する業務に従事しています。
ビックデータの収集や、蓄積、分析などの環境構築の経験はそこそこありますが、機械学習による予測や分類などのスキルは持ち合わせていませんでした。
今まで機械学習を避け続けてきましたが、一念発起し学ぼうと思います。

学び方としては、AWS Certified Machine Learning – Specialty（以降、ML試験という。）の勉強を通して、理解を深めていきます。ML試験のガイドの第２分野に、探索的データ解析が登場しましたのでそこから学びたいと思います。

今回は、以下のうち**次元低減**について学びたいと思います。

> 特徴エンジニアリングの概念を分析/評価する (データのビニング、トークナイゼーション、外れ値、合成的特徴、One-Hotエンコーディング、次元低減)

なお、過去の機械学習の調べてみたシリースは下記にまとめています。
- 2.探索的データ分析
- 2.1.モデリング用のデータをサニタイズおよび準備する
    - [【初心者】探索的データ解析とは何かを調べてみた](https://qiita.com/zumax/items/52c97307bf18f407bb6e)
    - [【初心者】データのスケーリングを調べてみた](https://qiita.com/zumax/items/ca7184dcf4e7fd242128)
    - [【初心者】データの拡張を調べてみた](https://qiita.com/zumax/items/0727e329f3322897d3e7)
    - [【初心者】データアノテーションを調べてみた](https://qiita.com/zumax/items/d0da86b68b05b99cb23e)
- 2.2.特徴エンジニアリングを実行する
    - [【初心者】特徴量エンジニアリングについて調べてみた](https://qiita.com/zumax/items/3b6e771ef1fcaf3edd91)
    - [【初心者】特徴量エンジニアリング（データのビニング）について調べてみた](https://qiita.com/zumax/items/dc0c86736dd5362cf118)
    - [【初心者】特徴量エンジニアリング（トークナイゼーション）について調べてみた。](https://qiita.com/zumax/items/5286c51ecc0a81b66b87)
    - [【初心者】特徴量エンジニアリング（外れ値）について調べてみた](https://qiita.com/zumax/items/2a07f6d3502fc9a16a44)
    - [【初心者】特徴量エンジニアリング（合成データ）について調べてみた](https://qiita.com/zumax/items/654eae53dae77f222433)
    - [【初心者】特徴量エンジニアリング（ダミー変数[One-Hotエンコーディング]）について調べてみた](https://qiita.com/zumax/items/de5cef1ac4a281400764)

- 機械学習プロセス
    - [【初心者】AWS Machine Learning Lensを整理する](https://qiita.com/zumax/items/93f9635b3be51fe483e1)

# まとめ
- 次元低減＝次元削減
- 次元削減の手段の一つとして主成分分析がある。
- 主成分分析では、特徴量を抽出し次元数を減らす。次元を減らすことにより可視化が可能になる。

# 概要
## 次元低減とは？
キカガクさんの[機械学習 実践（教師なし学習）](https://free.kikagaku.ai/tutorial/basic_of_machine_learning/learn/machine_learning_unsupervised)を参考に整理しています。ありがとうございます。

> 次元削減とは、例えば 4 次元のデータ（列数が 4 つのデータ）があった場合、2 次元などの低次元に落とし込むことを指します。また、一般的に次元削減は単にデータを削除するのではなく、可能な限り元のデータの情報を保持したまま、低次元のデータに変形を行います。

**以降、次元低減を次元削減と読み替えています。**
- 次元削減は、その名の通り次元数を削減することを指します。
- データを削除するのではなく、可能な限り元のデータの情報を保持したまま低次元データに変形する。
次元削減の1つの手法として、主成分分析がある。

## 主成分分析とは？
[次元削減とは？次元削減と主成分分析に関して学ぼう！](https://aiacademy.jp/media/?p=256)の内容も参考しています。ありがとうございます。
定義を以下に整理します。
- Principal Component Analysis(PCA)
- 主成分分析では、特徴量を抽出することによって、データセット内の特徴量を削減することができる。
- 高次元（多次元）データを低次元化する手法
- 低次元化することにより可視化もできる。（可視化するための手法。）
- 教師なし学習の一つ
- **特徴量を選択するのではなく、抽出する。**
- 抽出は、非可逆的なもの。（元のデータセットの特徴量には戻らない。）
- 分散により次元の重要度を決める。
    - 分散が大きいほどデータのばらつきは大きい
    - 分散が小さいほどデータのばらつきは小さい

${例） y=2x+1}$の１次関数で考える。
- プロットする点は、(2,5),(3,7),(5,11),(7,15)、これらの点をx軸y軸に射影してそれぞれの分散を求める。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/34331a2e-b357-f0b1-fb59-f4b271ea590b.png)


※出典：[次元削減とは？次元削減と主成分分析に関して学ぼう！](https://aiacademy.jp/media/?p=256)から抜粋

主成分分析する前の分散について考えると、
x軸に射影したときの分散は、3.69(3.6875)、y軸に射影したときの分散は14.75。

<details><summary>※ 参考</summary><div>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/17b3b446-5e4e-999e-64e6-3ebc54c11e9e.png)
</div></details>

それぞれのxとyが相関していることは明らかであるため、2次元から1次元への圧縮を考える。
新しい次元Z1は以下のとおりです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/860b11e8-1649-8b6a-4e1f-da937e652c4f.png)

※出典：[次元削減とは？次元削減と主成分分析に関して学ぼう！](https://aiacademy.jp/media/?p=256)から抜粋

- 新しく抽出した次元に射影したデータの分散は、x軸y軸へ射影したときよりも間隔（ばらつき）が大きいので分散が大きいことが分かる。

さらに、この次元に直行する新しい次元についても考える。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/49374ba0-4cce-a0dd-a62a-d7c76ecb0f17.png)
※出典：[次元削減とは？次元削減と主成分分析に関して学ぼう！](https://aiacademy.jp/media/?p=256)から抜粋

- この次元では全てのデータの間隔(ばらつき)が0なので、情報が全く含まれていないことが分かる。

以下は、キカガクさんの説明を載せています。こちらも合わせて見ると少し理解が深まりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/2cb7473b-d1ce-616c-3101-c768c86f05f3.png)

※出典：[機械学習 実践（教師なし学習）](https://free.kikagaku.ai/tutorial/basic_of_machine_learning/learn/machine_learning_unsupervised)から抜粋

さらに、[こちら](https://logics-of-blue.com/principal-components-analysis/)の記事がとてもわかり易かったです。ありがとうございます。
> 散布図にそれっぽい線（軸）を引くこと
> この線は、データのばらつき、すなわち分散を最大にするように引かれています。

- 第一主成分軸が、ばらつきが最大化される、第二主成分軸が、ばらつきが2番目に大きい。


> この線が引っ張れると、とてもうれしいことがあります。
それは「データを一つ一つ見なくても、データの概要をつかむことができる」ことです。
> 主成分分析ができると、データの要約ができます。

- データの要約ができて、ぱっと見で分かる。

> 主成分分析ですと、様々な要素をひとまとめにできるので、例えば「収入が多く購買意欲も高いユーザー」など複数の要素を組み合わせて一つのカテゴリとして扱うことができるようになります。

- 〇〇✕△△の組わせで1つのカテゴリとして扱える。

### 主成分分析の結果はどのように解釈すればよいか
> まず『データの要約』という観点から見ると、主成分軸の「寄与率」を理解することが重要です。
> 寄与率とは、下の図のように「この主成分軸一つで、データの何割を説明することができているか」を表したものです。

- 主成分分割の解釈の一つは寄与率がある。寄与率は、主成分軸の1つでデータの何割を説明することができるか。


# 実践
## データセットの準備
scikit-learnのIrisのデータセットを使用します。

```
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

from sklearn.datasets import load_iris
```

データセットを確認します。
```
dataset = load_iris()
x = dataset.data
t = dataset.target
feature_names = dataset.feature_names

pd.DataFrame(x, columns=feature_names).head()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/c721594d-9715-37f9-c257-0d6cede57516.png)
- データを見ると4次元ということが分かります。これを2次元に落とし込みます。

## モデルの定義と学習
```
from sklearn.decomposition import PCA
pca = PCA(n_components=2, random_state=0)
```
- n_componentsは次元削減後の次元数とのこと。
- 4次元から2次元に落とし込むため、パラメータは2を指定しています。
- なお、2次元にすることで可視化も可能になります。


モデルの学習では、主成分分析を適用するために必要な分散を求めます。教師なし学習では正解となる指標がないため、主成分分析では実測値の分散を用いて求めます。
```
pca.fit(x)

# 分散の確認
pca.get_covariance()

```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/991c73de-32b1-25cf-ff5c-1223c0ba08c9.png)

- scikit-learnでは`.fit()`メソッドで分散を算出する。`n_components=2`としているので第二主成分まで出力します。

## 変換

データを変換（写像）するには`.transform`メソッドを使用します。
**写像とは、元のデータを主成分軸上へと写すこと**をいう。

以下の図は、写像のイメージです。わかりやすい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/f7785b34-f602-65cd-601a-7ae85cea6957.png)
※出典：[次元削減とは？次元削減と主成分分析に関して学ぼう！](https://aiacademy.jp/media/?p=256)から抜粋

- `transform`により、第一主成分と第二主成分に写す。

主成分分析を適用します。
```

x_transformed = pca.transform(x)
```
主成分分析適用後のデータの確認します。
```
pd.DataFrame(x_transformed, columns=['第一主成分', '第二主成分']).head(10)

```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/0b259ea3-7f2a-3113-74ac-ee81e722b3e0.png)

- データが二次元に落とし込まれることが分かりました。
- 1列目のデータが第一主成分、2列目のデータが第二主成分とよびます。それぞれの列は次元削減前の情報を持ち、それぞれの列が保持する元データの情報の割合を**寄与率(Proportion of the variance)**と呼びます。
- 寄与率は`fit()`メソッド後のexplained_variance_ratio_属性からそれぞれの寄与率を確認することが出来ます。

```
第一主成分の寄与率：0.9246187232017271
第二主成分の寄与率：0.05306648311706782
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/856d42ca-5b15-11fe-2812-ead22e2aa99a.png)
- 第一主成分は92%、第２主成分は5%ほどの寄与率ということが分かりました。
- **97%程度の割合で、元のデータの情報を保持したまま削減できていることが確認できる。**

::: note info
主成分分析は100%情報を保持したまま次元削減するのではなく、いつからの情報を保持できていないことが分かる。
**主成分分析を適用したあとは、この寄与率を確認し、元データをどの程度再現できているかを確認することが重要。**
:::

## 可視化
次元削減後のデータを可視化します。
Irisのデータセットは3種類あります。可視化を行う際に、それぞれのクラスに色を付けて表示し、次元削減後のデータを確認します。
```
np.unique(t)
```
次元削減後のデータを可視化します。
```
sns.scatterplot(x_transformed[:, 0], x_transformed[:, 1], 
             hue=t, palette=sns.color_palette(n_colors=3));
```
- `sns_color_palette(n_colors=3)`で色を3種類に分けている。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/ff9a5d90-b02a-5370-dfb9-0d290d6154fd.png)
- 次元削減を行うことでデータセットを可視化することが出来ました。
- この様に可視化することにより、手元データを直感的に理解できることは重要です。
    - 例えば
        - クラス1(オレンジ)とクラス2(緑)は分類することは少し困難であることは想定できます。
        - クラス0(青)は、機械学習を用いることなく分類を行うことも可能であることが分かる。

:::note warn
上記の関数（sns.scatterplot）でxとyの値を明示的に指定するようにとwarningが出たが、表示されたのでこのまま先に進めます。
:::

## 標準化の適用

主成分分析を行う際には、必ず標準化を行うこと。標準化は平均を0、分散（標準偏差）を1とする操作。
```

from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
x_scaled = scaler.fit_transform(x)

```

モデルの定義から主成分分析適用後のデータの確認まで行います。
```

pca = PCA(n_components=2, random_state=0)

x_std_transformed = pca.fit_transform(x_scaled)

pd.DataFrame(x_std_transformed, columns=['第一主成分', '第二主成分']).head(10)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/ed553c03-81db-f95d-d2ec-bd6b58c8fd48.png)


```
# 寄与率
print('第一主成分の寄与率：{}'.format(pca.explained_variance_ratio_[0]))
print('第二主成分の寄与率：{}'.format(pca.explained_variance_ratio_[1]))

```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/cf59f720-a9b8-3f9c-b208-9102a0b70a1b.png)
先ほどと寄与率が異なっている。
- 第一主成分が0.92→0.72になっている。
- 第二主成分が0.05→0.22になっている。
**全体の情報損失も大きくなっている。97%程度から94%程度の割合に減っている。*

次元削減後のデータを可視化します。
```
sns.scatterplot(x_std_transformed[:, 0], x_std_transformed[:, 1], 
             hue=t, palette=sns.color_palette(n_colors=3));
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/44d1dc31-6475-e1ad-41e0-7733204323ef.png)

2つの結果を並べて可視化して違いを確認します。
```
fig = plt.figure(figsize=(7, 10))

ax1 = fig.add_subplot(2, 1, 1)
sns.scatterplot(x_transformed[:, 0], x_transformed[:, 1], 
             hue=t, palette=sns.color_palette(n_colors=3));
ax1.set_title('Before')

ax2 = fig.add_subplot(2, 1, 2)
sns.scatterplot(x_std_transformed[:, 0], x_std_transformed[:, 1], 
             hue=t, palette=sns.color_palette(n_colors=3));
ax2.set_title('After');
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206276/4f4eb766-840a-43ff-17f2-cf8a70fff355.png)

変換点は以下のとおりです。
- yのスケールが1.5から2に変わった。
- xのスケールが4から3に変わった。
- 1（オレンジ）と2（緑）がより近づいた。

# 考察
今回は、次元削減の一つの手法である主成分分析を学びました。
主成分分析は、多次元データを削減しデータを可視化するための手段と理解しました。
この他にも手法があるようなので、今後学習していきたいと思います。

# 参考

https://aiacademy.jp/media/?p=256

https://free.kikagaku.ai/tutorial/basic_of_machine_learning/learn/machine_learning_unsupervised

https://logics-of-blue.com/principal-components-analysis/