ラビットチャレンジレポート #9 主成分分析

# 主成分分析
* 多変量データの持つ構造をより少数個の指標に圧縮
    * つまり、次元の縮小を行う
    * 変量の個数を減らすことに伴う、情報の損失をなるべく小さくしたい
    * 少数変数を利用した分析や可視化が実現可能

* 次元の縮小とは？
    * 国語、数学、英語という3次元を総合点にまとめることで1次元に縮小することができる

### 係数ベクトルが変われば線形変換後の値が変化
* 情報の量を分散の大きさと考える
* 線形変換後の変数の分散が最大となる射影軸を探索
    * データのばらつきが大きいほど元のデータの情報を多く含んでいると考えられるから
* 線形変換後の分散

```math
Var(s_j)= \frac{1}{n}s_j^Ts_j \\
= \frac{1}{n}(\bar{X}a_j)^T(\bar{X}a_j) \\
= \frac{1}{n}a_j^T\bar{X}\bar{X}a_j \\
=a_j^TVar(\bar{X})a_j
```

### 制約付き最適化問題を解く
* ノルムが1となる制約を入れる
    * 制約を入れないと無限に解がある

* 目的関数

```math
arg max a_j^TVar(\bar{X})a_j
```

* 制約条件

```math
a_j^Ta_j = 1
```

* 制約付き最適化問題の解き方
    * ラグランジュ関数を最大にする係数vベクトルを探索
    * 微分して0になる点を探すということ
    * ラグランジュ関数は下記

```math
E(a_j) = a_j^TVar(\bar(X))a_j- \lambda(a_j^Ta_j-1)
```

* ラグランジュ関数を微分して最適解を求める
    * 元のデータの共分散分散行列の固有値と固有ベクトルが上記の制約付き最適化問題の解となる

```math
Var(\bar(X))a_j= \lambda a_j
```

* 射影先の分散は固有値と一致
* 共分散分散行列は正定値対象行列
    * 固有値は必ず0以上
    * 固有ベクトルは直行

## 寄与率
* 第1~元次元分の主成分の分散は元のデータの分散と一致
    * 2次元のデータを2次元の主成分で表示したとき、固有値の和と元のデータの分散が一致
    * 第k主成分の分散は主成分に対応する固有値

```math
V_{total}=\sum^m_{i=1} \lambda_i
```

*  **寄与率**：第k主成分の分散の全分散に対する割合（第k主成分が持つ情報量の割合）
*  **累積寄与率**：第1-k主成分までに圧縮した際の情報損失量の割合

# 実装演習
* こんな感じのデータで実際に触っていく

```python
cancer_df.head()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2183979/2acf1ad6-48c5-12c1-0051-4212ad5de52e.png)


* `Unnamed: 32`をもつ行を削除

```python
cancer_df.drop('Unnamed: 32', axis=1, inplace=True)
```

```python
# 目的変数の抽出
y = cancer_df.diagnosis.apply(lambda d: 1 if d == 'M' else 0)
# 説明変数の抽出
X = cancer_df.loc[:, 'radius_mean':]

# 学習用とテスト用でデータを分離
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)

# 標準化
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# ロジスティック回帰で学習
logistic = LogisticRegressionCV(cv=10, random_state=0)
logistic.fit(X_train_scaled, y_train)

# 検証
print('Train score: {:.3f}'.format(logistic.score(X_train_scaled, y_train)))
# Train score: 0.988

print('Test score: {:.3f}'.format(logistic.score(X_test_scaled, y_test)))
# Test score: 0.972

print('Confustion matrix:\n{}'.format(confusion_matrix(y_true=y_test, y_pred=logistic.predict(X_test_scaled))))
# Confustion matrix:
[[89  1]
 [ 3 50]]
```

* 学習データでのスコアが98.8%でテストデータのスコアは97.2%とかなりよさそう

```python
pca = PCA(n_components=30)
pca.fit(X_train_scaled)
plt.bar([n for n in range(1, len(pca.explained_variance_ratio_)+1)], pca.explained_variance_ratio_)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2183979/24515f6c-2874-4206-accb-cbf085496839.png)

```python
# PCA
# 次元数2まで圧縮
pca = PCA(n_components=2)
X_train_pca = pca.fit_transform(X_train_scaled)
print('X_train_pca shape: {}'.format(X_train_pca.shape))
# X_train_pca shape: (426, 2)

# 寄与率
print('explained variance ratio: {}'.format(pca.explained_variance_ratio_))
# explained variance ratio: [ 0.43315126  0.19586506]

# 散布図にプロット
temp = pd.DataFrame(X_train_pca)
temp['Outcome'] = y_train.values
b = temp[temp['Outcome'] == 0]
m = temp[temp['Outcome'] == 1]
plt.scatter(x=b[0], y=b[1], marker='o') # 良性は○でマーク
plt.scatter(x=m[0], y=m[1], marker='^') # 悪性は△でマーク
plt.xlabel('PC 1') # 第1主成分をx軸
plt.ylabel('PC 2') # 第2主成分をy軸
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2183979/b58f9409-8d2e-304f-2f8d-3cad795f61eb.png)