主成分分析を Python で理解する

主成分分析（principal component analysis）とは多変量解析手法のうち次元削減手法としてよく用いられる手法の一種で、相関のある多変数から、相関のない少数で全体のばらつきを最もよく表す変数を合成します。

主成分分析を行う便利なツールとして、Pythonで利用可能なScikit-learnなどがありますが、ここではScikit-learnでのPCAの使い方を概観したあと、Scikit-learnを使わずにpandasとnumpyだけでPCAをしてみることで、Pythonの勉強とPCAの勉強を同時に行いたいと思います。

プログラミングにおいて大事なのは「コピペ・タブ補完・ヒストリー機能を極力使うこと」、「一字一句を理解できないと先に進めないのではなく、まずは全部を理解できなくてもいいからゴールまで辿り着き、中身の理解はその後ですること」、「出来上がっているコードの中で、どこを改変すれば自分の目的を達成できるか学ぶこと」、「ときどき変数の中身をチェックすること」などです。頑張ってください。

# ワインのデータを例に

データは <a href="http://archive.ics.uci.edu/ml/datasets/Wine">UC Irvine Machine Learning Repository</a> から取得したものを少し改変しました。

https://raw.githubusercontent.com/maskot1977/ipython_notebook/master/toydata/wine.txt

## ライブラリのインポート


```python
# 数値計算やデータフレーム操作に関するライブラリをインポートする
import numpy as np
import pandas as pd
```


```python
# URL によるリソースへのアクセスを提供するライブラリをインポートする。
import urllib.request 
```


```python
# 図やグラフを図示するためのライブラリをインポートする。
import matplotlib.pyplot as plt
%matplotlib inline
```


```python
import sklearn #機械学習のライブラリ
from sklearn.decomposition import PCA #主成分分析器
```

## データのダウンロード


```python
url = "https://raw.githubusercontent.com/maskot1977/ipython_notebook/master/toydata/wine.txt"
urllib.request.urlretrieve(url, 'wine.txt') 
```




    ('wine.txt', <http.client.HTTPMessage at 0x11d029198>)



## データの読み込みと確認


```python
df = pd.read_csv("wine.txt", sep="\t", index_col=0)
```


```python
df.head()
```

<div>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>class</th>
      <th>Alcohol</th>
      <th>Malic acid</th>
      <th>Ash</th>
      <th>Alcalinity of ash</th>
      <th>Magnesium</th>
      <th>Total phenols</th>
      <th>Flavanoids</th>
      <th>Nonflavanoid phenols</th>
      <th>Proanthocyanins</th>
      <th>Color intensity</th>
      <th>Hue</th>
      <th>OD280/OD315 of diluted wines</th>
      <th>Proline</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>1</td>
      <td>14.23</td>
      <td>1.71</td>
      <td>2.43</td>
      <td>15.6</td>
      <td>127</td>
      <td>2.80</td>
      <td>3.06</td>
      <td>0.28</td>
      <td>2.29</td>
      <td>5.64</td>
      <td>1.04</td>
      <td>3.92</td>
      <td>1065</td>
    </tr>
    <tr>
      <th>1</th>
      <td>1</td>
      <td>13.20</td>
      <td>1.78</td>
      <td>2.14</td>
      <td>11.2</td>
      <td>100</td>
      <td>2.65</td>
      <td>2.76</td>
      <td>0.26</td>
      <td>1.28</td>
      <td>4.38</td>
      <td>1.05</td>
      <td>3.40</td>
      <td>1050</td>
    </tr>
    <tr>
      <th>2</th>
      <td>1</td>
      <td>13.16</td>
      <td>2.36</td>
      <td>2.67</td>
      <td>18.6</td>
      <td>101</td>
      <td>2.80</td>
      <td>3.24</td>
      <td>0.30</td>
      <td>2.81</td>
      <td>5.68</td>
      <td>1.03</td>
      <td>3.17</td>
      <td>1185</td>
    </tr>
    <tr>
      <th>3</th>
      <td>1</td>
      <td>14.37</td>
      <td>1.95</td>
      <td>2.50</td>
      <td>16.8</td>
      <td>113</td>
      <td>3.85</td>
      <td>3.49</td>
      <td>0.24</td>
      <td>2.18</td>
      <td>7.80</td>
      <td>0.86</td>
      <td>3.45</td>
      <td>1480</td>
    </tr>
    <tr>
      <th>4</th>
      <td>1</td>
      <td>13.24</td>
      <td>2.59</td>
      <td>2.87</td>
      <td>21.0</td>
      <td>118</td>
      <td>2.80</td>
      <td>2.69</td>
      <td>0.39</td>
      <td>1.82</td>
      <td>4.32</td>
      <td>1.04</td>
      <td>2.93</td>
      <td>735</td>
    </tr>
  </tbody>
</table>
</div>



第1列目の「class」というのが品種で、それ以降の列はいろんな観測値です。まずは第1列目以外の散布図行列を作り、第1列目で色分けすることにより、データを概観してみましょう。


```python
from pandas import plotting 
plotting.scatter_matrix(df.iloc[:, 1:], figsize=(8, 8), c=list(df.iloc[:, 0]), alpha=0.5)
plt.show()
```


![output_11_0.png](https://qiita-image-store.s3.amazonaws.com/0/211162/9bb292a7-0777-35cb-69c7-53ab1fef8238.png)



3品種の特徴がなんとなく分かれていることが見えてきますね。ですが、もっと少ない変数で特徴を説明できないでしょうか。

# scikit-learnで主成分分析

## 行列の標準化

（第1列目以外の）各列に対して、平均値を引いたものを標準偏差で割ります。


```python
# 行列の標準化
dfs = df.iloc[:, 1:].apply(lambda x: (x-x.mean())/x.std(), axis=0)
dfs.head()
```

<div>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>Alcohol</th>
      <th>Malic acid</th>
      <th>Ash</th>
      <th>Alcalinity of ash</th>
      <th>Magnesium</th>
      <th>Total phenols</th>
      <th>Flavanoids</th>
      <th>Nonflavanoid phenols</th>
      <th>Proanthocyanins</th>
      <th>Color intensity</th>
      <th>Hue</th>
      <th>OD280/OD315 of diluted wines</th>
      <th>Proline</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>1.514341</td>
      <td>-0.560668</td>
      <td>0.231400</td>
      <td>-1.166303</td>
      <td>1.908522</td>
      <td>0.806722</td>
      <td>1.031908</td>
      <td>-0.657708</td>
      <td>1.221438</td>
      <td>0.251009</td>
      <td>0.361158</td>
      <td>1.842721</td>
      <td>1.010159</td>
    </tr>
    <tr>
      <th>1</th>
      <td>0.245597</td>
      <td>-0.498009</td>
      <td>-0.825667</td>
      <td>-2.483841</td>
      <td>0.018094</td>
      <td>0.567048</td>
      <td>0.731565</td>
      <td>-0.818411</td>
      <td>-0.543189</td>
      <td>-0.292496</td>
      <td>0.404908</td>
      <td>1.110317</td>
      <td>0.962526</td>
    </tr>
    <tr>
      <th>2</th>
      <td>0.196325</td>
      <td>0.021172</td>
      <td>1.106214</td>
      <td>-0.267982</td>
      <td>0.088110</td>
      <td>0.806722</td>
      <td>1.212114</td>
      <td>-0.497005</td>
      <td>2.129959</td>
      <td>0.268263</td>
      <td>0.317409</td>
      <td>0.786369</td>
      <td>1.391224</td>
    </tr>
    <tr>
      <th>3</th>
      <td>1.686791</td>
      <td>-0.345835</td>
      <td>0.486554</td>
      <td>-0.806975</td>
      <td>0.928300</td>
      <td>2.484437</td>
      <td>1.462399</td>
      <td>-0.979113</td>
      <td>1.029251</td>
      <td>1.182732</td>
      <td>-0.426341</td>
      <td>1.180741</td>
      <td>2.328007</td>
    </tr>
    <tr>
      <th>4</th>
      <td>0.294868</td>
      <td>0.227053</td>
      <td>1.835226</td>
      <td>0.450674</td>
      <td>1.278379</td>
      <td>0.806722</td>
      <td>0.661485</td>
      <td>0.226158</td>
      <td>0.400275</td>
      <td>-0.318377</td>
      <td>0.361158</td>
      <td>0.448336</td>
      <td>-0.037767</td>
    </tr>
  </tbody>
</table>
</div>



## 主成分分析


```python
#主成分分析の実行
pca = PCA()
pca.fit(dfs)
# データを主成分空間に写像
feature = pca.transform(dfs)
```

### 主成分得点

横軸が主成分(PC1, PC2, PC3, ....)、縦軸が各サンプルになります。


```python
# 主成分得点
pd.DataFrame(feature, columns=["PC{}".format(x + 1) for x in range(len(dfs.columns))]).head()
```

<div>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>PC1</th>
      <th>PC2</th>
      <th>PC3</th>
      <th>PC4</th>
      <th>PC5</th>
      <th>PC6</th>
      <th>PC7</th>
      <th>PC8</th>
      <th>PC9</th>
      <th>PC10</th>
      <th>PC11</th>
      <th>PC12</th>
      <th>PC13</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>3.307421</td>
      <td>-1.439402</td>
      <td>-0.165273</td>
      <td>-0.215025</td>
      <td>0.691093</td>
      <td>-0.223250</td>
      <td>0.594749</td>
      <td>0.064956</td>
      <td>0.639638</td>
      <td>1.018084</td>
      <td>-0.450293</td>
      <td>0.539289</td>
      <td>-0.066052</td>
    </tr>
    <tr>
      <th>1</th>
      <td>2.203250</td>
      <td>0.332455</td>
      <td>-2.020757</td>
      <td>-0.290539</td>
      <td>-0.256930</td>
      <td>-0.924512</td>
      <td>0.053624</td>
      <td>1.021534</td>
      <td>-0.307978</td>
      <td>0.159252</td>
      <td>-0.142256</td>
      <td>0.387146</td>
      <td>0.003626</td>
    </tr>
    <tr>
      <th>2</th>
      <td>2.509661</td>
      <td>-1.028251</td>
      <td>0.980054</td>
      <td>0.722863</td>
      <td>-0.250327</td>
      <td>0.547731</td>
      <td>0.423012</td>
      <td>-0.343248</td>
      <td>-1.174521</td>
      <td>0.113042</td>
      <td>-0.285866</td>
      <td>0.000582</td>
      <td>0.021655</td>
    </tr>
    <tr>
      <th>3</th>
      <td>3.746497</td>
      <td>-2.748618</td>
      <td>-0.175696</td>
      <td>0.566386</td>
      <td>-0.310964</td>
      <td>0.114109</td>
      <td>-0.382259</td>
      <td>0.641783</td>
      <td>0.052397</td>
      <td>0.238739</td>
      <td>0.757448</td>
      <td>-0.241339</td>
      <td>-0.368444</td>
    </tr>
    <tr>
      <th>4</th>
      <td>1.006070</td>
      <td>-0.867384</td>
      <td>2.020987</td>
      <td>-0.408613</td>
      <td>0.297618</td>
      <td>-0.405376</td>
      <td>0.442825</td>
      <td>0.415528</td>
      <td>0.325900</td>
      <td>-0.078146</td>
      <td>-0.524466</td>
      <td>-0.216055</td>
      <td>-0.079140</td>
    </tr>
  </tbody>
</table>
</div>




```python
# 第一主成分と第二主成分でプロットする
plt.figure(figsize=(6, 6))
plt.scatter(feature[:, 0], feature[:, 1], alpha=0.8, c=list(df.iloc[:, 0]))
plt.grid()
plt.xlabel("PC1")
plt.ylabel("PC2")
plt.show()
```


![output_19_0.png](https://qiita-image-store.s3.amazonaws.com/0/211162/ceb43e7d-7e91-944a-d464-83c2f9f071f4.png)


第二主成分(PC2)までで、十分に3品種の区別ができそうです。


```python
from pandas import plotting 
plotting.scatter_matrix(pd.DataFrame(feature, 
                        columns=["PC{}".format(x + 1) for x in range(len(dfs.columns))]), 
                        figsize=(8, 8), c=list(df.iloc[:, 0]), alpha=0.5) 
plt.show()
```

![output_21_0.png](https://qiita-image-store.s3.amazonaws.com/0/211162/7c842394-9c9f-7c33-06b0-5d99f33cfbcf.png)


3品種を区別するだけの目的なら、第2主成分までで何とかなりそうです。それ以降の主成分は、意味はあるかもしれませんが、少なくとも3品種を区別するための役には立たなさそうです。


### 寄与率と累積寄与率

寄与率と累積寄与率は、第何主成分まででどのくらいの情報を説明できるかという指標です。


```python
# 寄与率
pd.DataFrame(pca.explained_variance_ratio_, index=["PC{}".format(x + 1) for x in range(len(dfs.columns))])
```

<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>0</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>PC1</th>
      <td>0.361988</td>
    </tr>
    <tr>
      <th>PC2</th>
      <td>0.192075</td>
    </tr>
    <tr>
      <th>PC3</th>
      <td>0.111236</td>
    </tr>
    <tr>
      <th>PC4</th>
      <td>0.070690</td>
    </tr>
    <tr>
      <th>PC5</th>
      <td>0.065633</td>
    </tr>
    <tr>
      <th>PC6</th>
      <td>0.049358</td>
    </tr>
    <tr>
      <th>PC7</th>
      <td>0.042387</td>
    </tr>
    <tr>
      <th>PC8</th>
      <td>0.026807</td>
    </tr>
    <tr>
      <th>PC9</th>
      <td>0.022222</td>
    </tr>
    <tr>
      <th>PC10</th>
      <td>0.019300</td>
    </tr>
    <tr>
      <th>PC11</th>
      <td>0.017368</td>
    </tr>
    <tr>
      <th>PC12</th>
      <td>0.012982</td>
    </tr>
    <tr>
      <th>PC13</th>
      <td>0.007952</td>
    </tr>
  </tbody>
</table>


```python
# 累積寄与率を図示する
import matplotlib.ticker as ticker
plt.gca().get_xaxis().set_major_locator(ticker.MaxNLocator(integer=True))
plt.plot([0] + list( np.cumsum(pca.explained_variance_ratio_)), "-o")
plt.xlabel("Number of principal components")
plt.ylabel("Cumulative contribution rate")
plt.grid()
plt.show()
```

![output_25_0.png](https://qiita-image-store.s3.amazonaws.com/0/211162/04bd0305-5bb5-e708-de13-dd970474e030.png)


### 固有値と固有ベクトル

各主成分の固有値は以下のとおりになります。


```python
# PCA の固有値
pd.DataFrame(pca.explained_variance_, index=["PC{}".format(x + 1) for x in range(len(dfs.columns))])
```




<div>

<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>0</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>PC1</th>
      <td>4.705850</td>
    </tr>
    <tr>
      <th>PC2</th>
      <td>2.496974</td>
    </tr>
    <tr>
      <th>PC3</th>
      <td>1.446072</td>
    </tr>
    <tr>
      <th>PC4</th>
      <td>0.918974</td>
    </tr>
    <tr>
      <th>PC5</th>
      <td>0.853228</td>
    </tr>
    <tr>
      <th>PC6</th>
      <td>0.641657</td>
    </tr>
    <tr>
      <th>PC7</th>
      <td>0.551028</td>
    </tr>
    <tr>
      <th>PC8</th>
      <td>0.348497</td>
    </tr>
    <tr>
      <th>PC9</th>
      <td>0.288880</td>
    </tr>
    <tr>
      <th>PC10</th>
      <td>0.250902</td>
    </tr>
    <tr>
      <th>PC11</th>
      <td>0.225789</td>
    </tr>
    <tr>
      <th>PC12</th>
      <td>0.168770</td>
    </tr>
    <tr>
      <th>PC13</th>
      <td>0.103378</td>
    </tr>
  </tbody>
</table>
</div>



各主成分の固有ベクトルは以下のとおりになります。縦軸の数字が主成分になります。


```python
# PCA の固有ベクトル
pd.DataFrame(pca.components_, columns=df.columns[1:], index=["PC{}".format(x + 1) for x in range(len(dfs.columns))])
```




<div>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>Alcohol</th>
      <th>Malic acid</th>
      <th>Ash</th>
      <th>Alcalinity of ash</th>
      <th>Magnesium</th>
      <th>Total phenols</th>
      <th>Flavanoids</th>
      <th>Nonflavanoid phenols</th>
      <th>Proanthocyanins</th>
      <th>Color intensity</th>
      <th>Hue</th>
      <th>OD280/OD315 of diluted wines</th>
      <th>Proline</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>PC1</th>
      <td>0.144329</td>
      <td>-0.245188</td>
      <td>-0.002051</td>
      <td>-0.239320</td>
      <td>0.141992</td>
      <td>0.394661</td>
      <td>0.422934</td>
      <td>-0.298533</td>
      <td>0.313429</td>
      <td>-0.088617</td>
      <td>0.296715</td>
      <td>0.376167</td>
      <td>0.286752</td>
    </tr>
    <tr>
      <th>PC2</th>
      <td>-0.483652</td>
      <td>-0.224931</td>
      <td>-0.316069</td>
      <td>0.010591</td>
      <td>-0.299634</td>
      <td>-0.065040</td>
      <td>0.003360</td>
      <td>-0.028779</td>
      <td>-0.039302</td>
      <td>-0.529996</td>
      <td>0.279235</td>
      <td>0.164496</td>
      <td>-0.364903</td>
    </tr>
    <tr>
      <th>PC3</th>
      <td>-0.207383</td>
      <td>0.089013</td>
      <td>0.626224</td>
      <td>0.612080</td>
      <td>0.130757</td>
      <td>0.146179</td>
      <td>0.150682</td>
      <td>0.170368</td>
      <td>0.149454</td>
      <td>-0.137306</td>
      <td>0.085222</td>
      <td>0.166005</td>
      <td>-0.126746</td>
    </tr>
    <tr>
      <th>PC4</th>
      <td>-0.017856</td>
      <td>0.536890</td>
      <td>-0.214176</td>
      <td>0.060859</td>
      <td>-0.351797</td>
      <td>0.198068</td>
      <td>0.152295</td>
      <td>-0.203301</td>
      <td>0.399057</td>
      <td>0.065926</td>
      <td>-0.427771</td>
      <td>0.184121</td>
      <td>-0.232071</td>
    </tr>
    <tr>
      <th>PC5</th>
      <td>-0.265664</td>
      <td>0.035214</td>
      <td>-0.143025</td>
      <td>0.066103</td>
      <td>0.727049</td>
      <td>-0.149318</td>
      <td>-0.109026</td>
      <td>-0.500703</td>
      <td>0.136860</td>
      <td>-0.076437</td>
      <td>-0.173615</td>
      <td>-0.101161</td>
      <td>-0.157869</td>
    </tr>
    <tr>
      <th>PC6</th>
      <td>-0.213539</td>
      <td>-0.536814</td>
      <td>-0.154475</td>
      <td>0.100825</td>
      <td>-0.038144</td>
      <td>0.084122</td>
      <td>0.018920</td>
      <td>0.258594</td>
      <td>0.533795</td>
      <td>0.418644</td>
      <td>-0.105983</td>
      <td>-0.265851</td>
      <td>-0.119726</td>
    </tr>
    <tr>
      <th>PC7</th>
      <td>-0.056396</td>
      <td>0.420524</td>
      <td>-0.149171</td>
      <td>-0.286969</td>
      <td>0.322883</td>
      <td>-0.027925</td>
      <td>-0.060685</td>
      <td>0.595447</td>
      <td>0.372139</td>
      <td>-0.227712</td>
      <td>0.232076</td>
      <td>-0.044764</td>
      <td>0.076805</td>
    </tr>
    <tr>
      <th>PC8</th>
      <td>-0.396139</td>
      <td>-0.065827</td>
      <td>0.170260</td>
      <td>-0.427970</td>
      <td>0.156361</td>
      <td>0.405934</td>
      <td>0.187245</td>
      <td>0.233285</td>
      <td>-0.368227</td>
      <td>0.033797</td>
      <td>-0.436624</td>
      <td>0.078108</td>
      <td>-0.120023</td>
    </tr>
    <tr>
      <th>PC9</th>
      <td>0.508619</td>
      <td>-0.075283</td>
      <td>-0.307694</td>
      <td>0.200449</td>
      <td>0.271403</td>
      <td>0.286035</td>
      <td>0.049578</td>
      <td>0.195501</td>
      <td>-0.209145</td>
      <td>0.056218</td>
      <td>0.085828</td>
      <td>0.137227</td>
      <td>-0.575786</td>
    </tr>
    <tr>
      <th>PC10</th>
      <td>0.211605</td>
      <td>-0.309080</td>
      <td>-0.027125</td>
      <td>0.052799</td>
      <td>0.067870</td>
      <td>-0.320131</td>
      <td>-0.163151</td>
      <td>0.215535</td>
      <td>0.134184</td>
      <td>-0.290775</td>
      <td>-0.522399</td>
      <td>0.523706</td>
      <td>0.162116</td>
    </tr>
    <tr>
      <th>PC11</th>
      <td>-0.225917</td>
      <td>0.076486</td>
      <td>-0.498691</td>
      <td>0.479314</td>
      <td>0.071289</td>
      <td>0.304341</td>
      <td>-0.025694</td>
      <td>0.116896</td>
      <td>-0.237363</td>
      <td>0.031839</td>
      <td>-0.048212</td>
      <td>0.046423</td>
      <td>0.539270</td>
    </tr>
    <tr>
      <th>PC12</th>
      <td>-0.266286</td>
      <td>0.121696</td>
      <td>-0.049622</td>
      <td>-0.055743</td>
      <td>0.062220</td>
      <td>-0.303882</td>
      <td>-0.042899</td>
      <td>0.042352</td>
      <td>-0.095553</td>
      <td>0.604222</td>
      <td>0.259214</td>
      <td>0.600959</td>
      <td>-0.079402</td>
    </tr>
    <tr>
      <th>PC13</th>
      <td>0.014970</td>
      <td>0.025964</td>
      <td>-0.141218</td>
      <td>0.091683</td>
      <td>0.056774</td>
      <td>-0.463908</td>
      <td>0.832257</td>
      <td>0.114040</td>
      <td>-0.116917</td>
      <td>-0.011993</td>
      <td>-0.089889</td>
      <td>-0.156718</td>
      <td>0.014447</td>
    </tr>
  </tbody>
</table>
</div>

第一主成分と第二主成分における観測変数の寄与度をプロットすることにより、各成分が何を考慮した値なのかのヒントが得られます。


```python
# 第一主成分と第二主成分における観測変数の寄与度をプロットする
plt.figure(figsize=(6, 6))
for x, y, name in zip(pca.components_[0], pca.components_[1], df.columns[1:]):
    plt.text(x, y, name)
plt.scatter(pca.components_[0], pca.components_[1], alpha=0.8)
plt.grid()
plt.xlabel("PC1")
plt.ylabel("PC2")
plt.show()
```

![output_31_0.png](https://qiita-image-store.s3.amazonaws.com/0/211162/55f30acb-e826-7d95-cdd2-987567ad2562.png)

はい、とっても便利ですね。便利すぎて意味分かんないですね。


# 演習

勉強のために、成分数を減らします。以下の4つの変数だけ考えることにします。


```python
dfs = dfs[['Color intensity', 'Flavanoids', 'Alcohol', 'Proline']]
```


```python
#主成分分析を実行してください。
```


```python
# 第一主成分と第二主成分でプロットしてください。
```

![output_34_0.png](https://qiita-image-store.s3.amazonaws.com/0/211162/73846e7e-7589-e0b5-6a6b-420997e9ff3b.png)


```python
# PC1〜PC4 で散布図行列を描いてください。
```


![output_35_0.png](https://qiita-image-store.s3.amazonaws.com/0/211162/1158dce7-cd7d-9c30-2bb8-09c914f3a7fa.png)



```python
# 寄与率を計算してください。
```




<div>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>0</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>PC1</th>
      <td>0.533531</td>
    </tr>
    <tr>
      <th>PC2</th>
      <td>0.309520</td>
    </tr>
    <tr>
      <th>PC3</th>
      <td>0.084787</td>
    </tr>
    <tr>
      <th>PC4</th>
      <td>0.072162</td>
    </tr>
  </tbody>
</table>
</div>




```python
# 累積寄与率を図示してください。
```

![output_37_0.png](https://qiita-image-store.s3.amazonaws.com/0/211162/3f5c74a4-d2eb-73d7-23aa-3b8c740d1997.png)



```python
# 各主成分の固有値を計算してください。
```




<div>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>0</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>PC1</th>
      <td>2.134122</td>
    </tr>
    <tr>
      <th>PC2</th>
      <td>1.238082</td>
    </tr>
    <tr>
      <th>PC3</th>
      <td>0.339148</td>
    </tr>
    <tr>
      <th>PC4</th>
      <td>0.288648</td>
    </tr>
  </tbody>
</table>
</div>




```python
# 各主成分の固有ベクトルを計算してください。
```




<div>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>Color intensity</th>
      <th>Flavanoids</th>
      <th>Alcohol</th>
      <th>Proline</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>PC1</th>
      <td>0.409416</td>
      <td>0.325547</td>
      <td>0.605601</td>
      <td>0.599704</td>
    </tr>
    <tr>
      <th>PC2</th>
      <td>0.633932</td>
      <td>-0.725357</td>
      <td>0.168286</td>
      <td>-0.208967</td>
    </tr>
    <tr>
      <th>PC3</th>
      <td>0.636547</td>
      <td>0.566896</td>
      <td>-0.388715</td>
      <td>-0.349768</td>
    </tr>
    <tr>
      <th>PC4</th>
      <td>-0.159113</td>
      <td>0.215651</td>
      <td>0.673667</td>
      <td>-0.688731</td>
    </tr>
  </tbody>
</table>
</div>


```python
# 第一主成分と第二主成分でプロットする
plt.figure(figsize=(6, 6))
for x, y, name in zip(pca.components_[0], pca.components_[1], ['Color intensity', 'Flavanoids', 'Alcohol', 'Proline']):
    plt.text(x, y, name)
plt.scatter(pca.components_[0], pca.components_[1], alpha=0.8)
plt.grid()
plt.xlabel("PC1")
plt.ylabel("PC2")
plt.show()
```

![output_42_0.png](https://qiita-image-store.s3.amazonaws.com/0/211162/af37edfd-6839-f3d7-55ce-4d9c55e89057.png)


この固有ベクトルから、ある程度の解釈ができます。

第1主成分は、全ての観測値を正方向に加味した総合指標のようなもの（ワインにとって、全て正であることが良いとは限りませんが）であり、特に「アルコール濃度」「プロリン濃度」に重みを置いた指標になっています。

第2主成分は、「色の濃さ」を正に、「フラボノイド濃度」を負に評価した指標になっています。

このような指標は、ワインの特徴の違いを解釈する助けになるでしょう。

# scikit-learnなしで主成分分析

## まずは第1主成分(PC1)

### 相関行列


```python
# 相関行列
dfc = dfs.corr()
```


```python
dfc
```




<div>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>Color intensity</th>
      <th>Flavanoids</th>
      <th>Alcohol</th>
      <th>Proline</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>Color intensity</th>
      <td>1.000000</td>
      <td>-0.172379</td>
      <td>0.546364</td>
      <td>0.316100</td>
    </tr>
    <tr>
      <th>Flavanoids</th>
      <td>-0.172379</td>
      <td>1.000000</td>
      <td>0.236815</td>
      <td>0.494193</td>
    </tr>
    <tr>
      <th>Alcohol</th>
      <td>0.546364</td>
      <td>0.236815</td>
      <td>1.000000</td>
      <td>0.643720</td>
    </tr>
    <tr>
      <th>Proline</th>
      <td>0.316100</td>
      <td>0.494193</td>
      <td>0.643720</td>
      <td>1.000000</td>
    </tr>
  </tbody>
</table>
</div>



### 相関行列の固有値と固有ベクトル


```python
# 固有値と固有ベクトル
eig_val, eig_vec =np.linalg.eig(dfc)
```


```python
# 固有値
eig_val
```




    array([2.13412212, 1.23808176, 0.33914837, 0.28864774])




```python
# 固有ベクトル
eig_vec
```




    array([[-0.40941602,  0.63393186, -0.63654682,  0.15911338],
           [-0.32554699, -0.72535703, -0.56689587, -0.21565114],
           [-0.60560142,  0.16828625,  0.38871536, -0.67366685],
           [-0.59970376, -0.20896726,  0.34976791,  0.68873107]])



### 第1主成分の固有ベクトル


```python
# 相関行列の固有ベクトルの第1列を、主成分分析では「第1主成分(PC1)の固有ベクトル」と言います
eig_vec_pc1 = eig_vec[:, 0]
eig_vec_pc1
```




    array([-0.40941602, -0.32554699, -0.60560142, -0.59970376])




```python
# scikit-learn による計算結果と照合してください。正負が逆転することがありますが、気になさらずに。
```

### 第1主成分の主成分得点


```python
# 主成分得点(PC1)
pc1 = np.dot(dfs, eig_vec_pc1)
pc1
```




    array([-1.96158489, -0.84437069, -1.45764803, -3.37794671, -0.24091918,
           -2.97597478, -2.26455503, -1.98932577, -2.26730282, -1.95585222,
           -2.81622301, -1.97061483, -1.98429472, -2.67430795, -3.50890694,
           -2.22484682, -2.54821609, -2.06733131, -3.92689454, -0.99735336,
           -1.3296379 , -0.01685181, -1.13293227, -0.31004679, -0.47699845,
           -0.14615498, -1.39507959, -1.10478452, -1.17671713, -1.34387136,
           -2.08008249, -2.59856235, -0.96999543, -1.78804312, -1.05456986,
           -1.00453015, -0.59308299, -0.70670392, -0.53106241, -1.27140504,
           -1.10909632, -0.9287257 , -1.88349832, -0.12368722, -0.61303024,
           -1.77096318, -1.97864591, -1.75185362, -1.90835535, -2.84877329,
           -1.58715156, -2.01419305, -2.36441818, -2.23735474, -1.57147534,
           -1.58299377, -1.88433998, -1.76975075, -2.40377192,  1.9270171 ,
            1.24956142,  0.91404783,  0.0234326 ,  0.85137293,  1.82924743,
            0.48021577, -0.03299298,  0.99787085,  0.31203842,  1.27896044,
            0.97923499,  0.02610127,  0.45290031, -0.42439989,  0.80165057,
            1.97922727,  0.73459567,  1.99240963,  0.84559797,  1.03458206,
            2.01595296,  0.3132995 ,  1.56053876,  0.59352112,  1.59361297,
            1.27169865,  1.67795044,  1.9303867 ,  1.65173541,  1.64803881,
            1.83694882,  1.82331441,  1.25158389,  1.84183816,  2.03937735,
            0.38943876,  1.91078494,  1.36510168,  0.17364405,  1.35325951,
            1.0216329 ,  1.32968167,  1.45352786,  2.16910312,  0.91828738,
            1.73374721,  1.30366187,  1.10060892,  1.82347134,  1.29972473,
            1.70299948,  1.62358288,  1.41382298,  2.13804421,  1.67208756,
            2.62917697,  2.04921573,  1.7081619 ,  1.43277679,  1.88882534,
            1.46022922,  0.4508606 ,  1.65350546,  0.89366481,  1.61474424,
            1.60027154,  1.00988393,  1.73280081,  1.62324673,  1.55954937,
            0.75068685,  0.70639925,  0.69087459,  0.78452743,  0.95364189,
            0.48333879,  1.33270418,  1.26876675,  0.34433528,  0.90881451,
            0.91173787,  0.07157763,  0.66159608,  0.4297798 ,  0.20458922,
            0.39182207,  0.55453927,  0.32136008, -0.23377302, -0.242701  ,
           -0.37817409, -0.1305284 ,  0.41500516, -0.60792532,  0.54077128,
           -0.13050252, -0.42494476,  0.19835677, -2.00180696, -0.99489754,
            0.81376864, -0.05315963,  0.82288447,  0.56125632, -0.68905354,
            0.12034891, -0.86771637, -0.21979684, -0.68662254, -0.33467534,
            1.47200968,  0.3394088 , -1.0859315 , -0.52005519, -0.28283458,
           -0.84032362, -0.61304633, -0.80436788])




```python
# scikit-learn による計算結果と照合してください。正負が逆転することがありますが、気になさらずに。
```

### 第1主成分の固有値


```python
# 相関行列の固有値の第1成分を、主成分分析では「第1主成分(PC1)の固有値」と言います
eig_val_pc1 = eig_val[0]
eig_val_pc1
```




    2.1341221243556294




```python
# scikit-learn による計算結果と照合してください。
```

## 次に第2主成分 (PC2)

* PC1の影響を取り除いた相関行列2


```python
# 相関行列から、PC1の影響を取り除いた相関行列2を作成します
matrix = []
for d1 in eig_vec_pc1:
    mat = []
    for d2 in eig_vec_pc1:
        mat.append(d1 * d2)
    matrix.append(mat)
matrix = np.array(matrix)
dfc2 = dfc - matrix * eig_val_pc1
dfc2
```




<div>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>Color intensity</th>
      <th>Flavanoids</th>
      <th>Alcohol</th>
      <th>Proline</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>Color intensity</th>
      <td>0.642275</td>
      <td>-0.456824</td>
      <td>0.017224</td>
      <td>-0.207887</td>
    </tr>
    <tr>
      <th>Flavanoids</th>
      <td>-0.456824</td>
      <td>0.773824</td>
      <td>-0.183931</td>
      <td>0.077545</td>
    </tr>
    <tr>
      <th>Alcohol</th>
      <td>0.017224</td>
      <td>-0.183931</td>
      <td>0.217304</td>
      <td>-0.131354</td>
    </tr>
    <tr>
      <th>Proline</th>
      <td>-0.207887</td>
      <td>0.077545</td>
      <td>-0.131354</td>
      <td>0.232474</td>
    </tr>
  </tbody>
</table>
</div>



* PC1の影響を取り除いた相関行列2の固有値と固有ベクトル


```python
# 固有値と固有ベクトル を求めてください。
```

* 第2主成分(PC2)の固有ベクトル


```python
# 相関行列2の固有ベクトルの第1列を、主成分分析では「第2主成分(PC2)の固有ベクトル」と言います。
# 第2主成分(PC2)の固有ベクトルを求め、scikit-learn による計算結果と照合してください。
```

* 第2主成分(PC2)の主成分得点


```python
# 主成分得点(PC2)を求め、scikit-learn による計算結果と照合してください。
```

* 第2主成分(PC2)の固有値


```python
# 相関行列2の固有値の第1成分を、主成分分析では「第2主成分(PC2)の固有値」と言います
# 第2主成分(PC2)の固有値を求め、scikit-learn による計算結果と照合してください。
```

## 続いて第3主成分 (PC3)

* PC2の影響を取り除いた相関行列3


```python
# 相関行列2から、PC2の影響を取り除いた相関行列3を作成してください。
```




<div>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>Color intensity</th>
      <th>Flavanoids</th>
      <th>Alcohol</th>
      <th>Proline</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>Color intensity</th>
      <td>0.144728</td>
      <td>0.112479</td>
      <td>-0.114857</td>
      <td>-0.043877</td>
    </tr>
    <tr>
      <th>Flavanoids</th>
      <td>0.112479</td>
      <td>0.122416</td>
      <td>-0.032801</td>
      <td>-0.110119</td>
    </tr>
    <tr>
      <th>Alcohol</th>
      <td>-0.114857</td>
      <td>-0.032801</td>
      <td>0.182241</td>
      <td>-0.087815</td>
    </tr>
    <tr>
      <th>Proline</th>
      <td>-0.043877</td>
      <td>-0.110119</td>
      <td>-0.087815</td>
      <td>0.178411</td>
    </tr>
  </tbody>
</table>
</div>



* PC2の影響を取り除いた相関行列3の固有値と固有ベクトル


```python
# 固有値と固有ベクトルを求めてください。
```

* 第3主成分(PC3)の固有ベクトル


```python
# 相関行列3の固有ベクトルの第1列を、主成分分析では「第3主成分(PC3)の固有ベクトル」と言います
# 第3主成分(PC3)の固有ベクトルを求め、scikit-learn による計算結果と照合してください。
```

* 第3主成分(PC3)の主成分得点


```python
# 主成分得点(PC3)を求め、scikit-learn による計算結果と照合してください。
```

* 第3主成分(PC3)の固有値


```python
# 相関行列3の固有値の第1成分を、主成分分析では「第3主成分(PC3)の固有値」と言います
# 第3主成分(PC3)の固有値を求め、scikit-learn による計算結果と照合してください。
```

## 最後に第4主成分(PC4)

* PC3の影響を取り除いた相関行列4


```python
# 相関行列2から、PC2の影響を取り除いた相関行列3を作成してください。
```




<div>
<table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>Color intensity</th>
      <th>Flavanoids</th>
      <th>Alcohol</th>
      <th>Proline</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>Color intensity</th>
      <td>0.007308</td>
      <td>-0.009904</td>
      <td>-0.030940</td>
      <td>0.031632</td>
    </tr>
    <tr>
      <th>Flavanoids</th>
      <td>-0.009904</td>
      <td>0.013424</td>
      <td>0.041934</td>
      <td>-0.042872</td>
    </tr>
    <tr>
      <th>Alcohol</th>
      <td>-0.030940</td>
      <td>0.041934</td>
      <td>0.130996</td>
      <td>-0.133925</td>
    </tr>
    <tr>
      <th>Proline</th>
      <td>0.031632</td>
      <td>-0.042872</td>
      <td>-0.133925</td>
      <td>0.136920</td>
    </tr>
  </tbody>
</table>
</div>



* PC3の影響を取り除いた相関行列4の固有値と固有ベクトル


```python
# 固有値と固有ベクトルを求めてください。
```

* 第4主成分(PC4)の固有ベクトル


```python
# 相関行列4の固有ベクトルの第1列を、主成分分析では「第4主成分(PC4)の固有ベクトル」と言います
# 第4主成分(PC4)の固有ベクトルを求め、scikit-learn による計算結果と照合してください。
```

* 第4主成分(PC4)の主成分得点


```python
# 主成分得点(PC4)を求め、scikit-learn による計算結果と照合してください。
```

* 第4主成分(PC4)の固有値


```python
# 相関行列4の固有値の第1成分を、主成分分析では「第4主成分(PC4)の固有値」と言います
# 第4主成分(PC4)の固有値を求め、scikit-learn による計算結果と照合してください。
```

## 寄与率

各主成分の固有値を足し合わせて割合をとったものを「寄与率」といいます。


```python
eig_val_pca = np.array([eig_val_pc1, eig_val_pc2, eig_val_pc3, eig_val_pc4])
eig_val_pca
```




    array([2.13412212, 1.23808176, 0.33914837, 0.28864774])




```python
eig_val_pca / eig_val_pca.sum()
```




    array([0.53353053, 0.30952044, 0.08478709, 0.07216194])




```python
# scikit-learn による計算結果と照合してください。
```

# 課題

* 同じデータに対して Alcohol, Flavanoids, Nonflavanoid phenols, Proanthocyanins, Color intensity, Hue の6変数を使って主成分分析し、その結果について考察してください。scikit-learnを使って構いません。

* <a href="https://qiita.com/maskot1977/items/453eddf5aa154c04668c">実習用データ</a> にある 「都道府県別アルコール類の消費量」 のデータを主成分分析し、その結果の解釈をしてください。scikit-learnを使って構いません。