ポケモンデータ解析.py


# ポケットモンスター 教師なし機械学習・教師あり機械学習

私はポケモンに詳しくないので、ポケモンのデータを解析してみました。データセットは <a href="https://www.kaggle.com/abcsds/pokemon">Pokemon with stats</a> から取得。

# データ読み込み

```python
import pandas as pd # ライブラリ pandas をインポートし、以下 pd と呼ぶことにする。
```

詳細は <a href="https://qiita.com/maskot1977/items/1f6c51965b1bfc341e4b">タブ区切りデータ、コンマ区切りデータ等の読み込み</a> を参照のこと。


```python
# https://www.kaggle.com/abcsds/pokemon から取得した Pokemon.csv を読み込む。
df = pd.read_csv("Pokemon.csv") # df とは、 pandas の DataFrame 形式のデータを入れる変数として命名
```


```python
df.head() # 先頭５行を表示
```

<img width="645" alt="スクリーンショット 2019-06-14 11.25.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/363e3123-fef1-13f3-4932-cb790a89f15b.png">




https://www.kaggle.com/abcsds/pokemon によると、各カラム（列）は次のような意味らしいです。

* __#__: PokeDex index number
* __Name__: Name of the Pokemon
* __Type 1__: Type of pokemon
* __Type 2__: Other Type of Pokemon
* __Total__: Sum of Attack, Sp. Atk, Defense, Sp. Def, Speed and HP
* __HP__: Hit Points
* __Attack__: Attack Strength
* __Defense__: Defensive Strength
* __Sp. Atk__: Special Attack Strength
* __Sp. Def__: Special Defensive Strength
* __Speed__: Speed
* __Generation__: Number of generation
* __Legendary__: True if Legendary Pokemon False if not (more revision on mythical vs legendary needed)

<a href="https://pandas.pydata.org/pandas-docs/stable/user_guide/style.html">pandas 0.24.2 documentation » User Guide » Styling</a> を参考に、数字の大きさに応じて棒グラフを表示してみます。


```python
df.head(50).style.bar(subset=['Total', 'HP', 'Attack', 'Defense', 'Sp. Atk', 'Sp. Def', 'Speed'])
```

<img width="841" alt="スクリーンショット 2019-06-14 11.24.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/e363943e-bfeb-017b-a57e-0c18dd096373.png">



```python
df.describe() # 平均値、標準偏差、最小値、25%四分値、中央値、75%四分値、最大値をまとめて表示
```

<img width="605" alt="スクリーンショット 2019-06-14 11.29.52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/124c727c-7dfc-3205-9d93-d54fc2e42b87.png">


８００体のポケモンのデータをこれから概観していきます。

# 散布図行列

まずは、データの全体像を眺めるため、散布図行列を描いてみましょう。


```python
# Jupyter 上で絵を表示するためのマジックコマンド
%matplotlib inline 
import matplotlib.pyplot as plt # matplotlib.pyplot をインポートし、以下 plt と呼ぶ。
```


```python
# 散布図行列
from pandas.tools import plotting 
# from pandas import plotting # 新しいバージョンではこちらを
plotting.scatter_matrix(df.iloc[:, 4:11], figsize=(8, 8)) 
plt.show()
```

![output_10_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/b898f8ef-02df-ded7-5b6c-609f6bb867a4.png)

ポケモンのパラメータ（Total、HP、Attack、Defense、Sp. Atk、Sp. Def、Speed）間の関係が何となく見えてきましたね。これらのパラメータと、属性（Type 1）との間に関係はあるでしょうか？まずは属性が何種類あるかリストアップしてみましょう。


```python
type1s = list(set(list(df['Type 1'])))
```


```python
print(len(type1s), type1s)
```

    18 ['Ground', 'Bug', 'Grass', 'Fire', 'Normal', 'Fighting', 'Psychic', 'Electric', 'Water', 'Ice', 'Poison', 'Dark', 'Fairy', 'Rock', 'Steel', 'Flying', 'Ghost', 'Dragon']


属性は１８種類。これらと各パラメータとの間に関係があるかどうか、散布図行列に属性で色をつけてみましょう。


```python
cmap = plt.get_cmap('coolwarm')
colors = [cmap((type1s.index(c) + 1) / (len(type1s) + 2)) for c in df['Type 1'].tolist()]
plotting.scatter_matrix(df.iloc[:, 4:11], figsize=(8, 8), color=colors, alpha=0.5) 
plt.show()
```

![output_15_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/069e7365-cd29-d2fd-7593-9fcb046fac59.png)


、、、よく分かりませんね。ちょっと横道に逸れますが、色のつけ方を自分好みにしたければ下記のようにして設定できます。


```python
from matplotlib.colors import LinearSegmentedColormap
dic = {'red':   ((0, 0, 0), (0.5, 1, 1), (1, 1, 1)), 
       'green': ((0, 0, 0), (0.5, 1, 1), (1, 0, 0)), 
       'blue':  ((0, 1, 1), (0.5, 0, 0), (1, 0, 0))}

tricolor_cmap = LinearSegmentedColormap('tricolor', dic)
```


```python
cmap = tricolor_cmap
colors = [cmap((type1s.index(c) + 1) / (len(type1s) + 2)) for c in df['Type 1'].tolist()]
plotting.scatter_matrix(df.iloc[:, 4:11], figsize=(8, 8), color=colors) 
plt.show()
```

![output_18_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/7d2bf10c-af05-0b3f-def9-0f1de3ba24de.png)


、、、この色のつけ方が好みかどうかはさておき、どっちにしても、パラメータと属性との関係はよく分かりませんね。

# 相関行列

パラメータ間の関係は、散布図行列を描くのも良いですが、ピアソンの相関係数を使って表すこともできます。


```python
import numpy as np
pd.DataFrame(np.corrcoef(df.iloc[:, 4:11].T.values.tolist()), 
             columns=df.iloc[:, 4:11].columns, index=df.iloc[:, 4:11].columns)
```

<img width="422" alt="スクリーンショット 2019-06-14 11.34.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/f29fdd14-1ad6-e7da-b210-9f42d8c41635.png">



これでは全体を把握しづらいので、カラーマップとして表現してみましょう。


```python
corrcoef = np.corrcoef(df.iloc[:, 4:11].T.values.tolist())
plt.imshow(corrcoef, interpolation='nearest', cmap=plt.cm.coolwarm)
plt.colorbar(label='correlation coefficient')
tick_marks = np.arange(len(corrcoef))
plt.xticks(tick_marks, df.iloc[:, 4:11].columns, rotation=90)
plt.yticks(tick_marks, df.iloc[:, 4:11].columns)
plt.tight_layout()
```


![output_23_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/47c90f53-f22c-efe6-3cac-a81612f1ec71.png)



どのパラメータも互いに正の相関があるようですが、Defence（防御力）と Speed （スピード）の間にはほとんど相関がないようです。

相関行列も、先ほどの「自分好みの」配色にしてみましょう。


```python
corrcoef = np.corrcoef(df.iloc[:, 4:11].T.values.tolist())
plt.imshow(corrcoef, interpolation='nearest', cmap=tricolor_cmap)
plt.colorbar(label='correlation coefficient')
tick_marks = np.arange(len(corrcoef))
plt.xticks(tick_marks, df.iloc[:, 4:11].columns, rotation=90)
plt.yticks(tick_marks, df.iloc[:, 4:11].columns)
plt.tight_layout()
```


![output_25_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/cc3d9506-4f36-8894-8783-8636fc7aabc1.png)


、、、分かりにくくなってしまったかもしれませんが。

# バイオリンプロット

バイオリンプロットは各変数の分布を眺めるいわゆるひとつの便利な方法です。


```python
# バイオリンプロット
fig = plt.figure()
ax = fig.add_subplot(111)
ax.violinplot(df.iloc[:, 4:11].values.T.tolist())
ax.set_xticks([1, 2, 3, 4, 5, 6, 7]) #データ範囲のどこに目盛りが入るかを指定する
ax.set_xticklabels(df.columns[4:11], rotation=90)
plt.grid()
plt.show()
```


![output_28_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/57d3ca52-51bd-9a21-148a-906236fe5697.png)



属性ごとに、バイオリンプロットを描いてみましょう。それぞれのポケモンの強さの傾向の違いが見えるはずです。


```python
for index, type1 in enumerate(type1s):
    df2 = df[df['Type 1'] == type1]
    fig = plt.figure(figsize=(8, 4))
    ax = fig.add_subplot(1, 1, 1)
    plt.title(type1)
    ax.set_ylim([0, 260])
    ax.violinplot(df2.iloc[:, 5:11].values.T.tolist())
    ax.set_xticks([1, 2, 3, 4, 5, 6]) #データ範囲のどこに目盛りが入るかを指定する
    ax.set_xticklabels(df2.columns[5:11], rotation=90)
    plt.grid()
    plt.show()
```


![output_30_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/6ab3cfba-bae5-36d2-6b3a-4a994bff7efe.png)



![output_30_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/bbe92c8b-8c97-911b-bdfa-37651cc7d964.png)



![output_30_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/ec48c486-75fd-fcee-580e-adee4f8162e5.png)



![output_30_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/7863398b-e407-2455-cbb2-60123cf4bcc1.png)



![output_30_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/bc76dcb6-10ba-d8d4-ad0d-0c3801c33046.png)



![output_30_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/352c3374-fed3-e26c-a06d-0ee587eae455.png)



![output_30_6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/145598d5-1f99-49dd-306d-de6db918b235.png)



![output_30_7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/38c8a8ab-f3a0-8553-dd7a-28668d67c587.png)



![output_30_8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/2aecf038-7e57-96d6-da54-02464d8d01b9.png)


![output_30_9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/98194578-1df4-eff2-ca0f-29a47ce88d77.png)



![output_30_10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/77140061-6093-45f8-858f-1fd93567a204.png)



![output_30_11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/d394bca8-0f3a-81cc-650c-bd872670b413.png)



![output_30_12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/e25376b3-e6e9-85ec-565f-c50e69f40460.png)



![output_30_13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/9b41f076-af5c-9f5e-939f-2506175dde0d.png)



![output_30_14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/7c77691d-8df5-4b8f-28e6-daa38ecbb137.png)



![output_30_15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/6a490f4a-7c2a-a31a-3396-6814867dee71.png)



![output_30_16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/3e27e9cf-b337-0dd7-241c-781bad440f2a.png)



![output_30_17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/2eeb9d2e-a2b8-d6b8-2a5b-f02023ef904a.png)


Psychic は攻撃力含め総合的に高いものがいるとか、Steel は防御力が高めだとか、Flying の能力分布は上位の方に偏っているとか、Dragon は意外と防御力が低めだとか、いろんな傾向が読み取れます。

# 主成分分析

８００体のポケモンを主成分分析して、第一主成分と第二主成分を用いて２次元平面状にプロットしてみましょう。

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

今回のデータは、８００体のポケモンの特徴が、６種類の「観測変数」(x<sub>1</sub>, x<sub>2</sub>, x<sub>3</sub>, x<sub>4</sub>, x<sub>5</sub>, x<sub>6</sub>) で表されています。この6変数を説明変数とします。これに対し、PCAで合成する合成変数は「主成分得点」といい、次式のように線型結合で与えられます。「合成変数」と呼んだり「潜在変数」と呼んだりすることもあり、紛らわしいです。

y<sub>PC1</sub> = a<sub>1,1</sub> x<sub>1</sub> + a<sub>1,2</sub>  x<sub>2</sub> +  a<sub>1,3</sub> x<sub>3</sub> + a<sub>1,4</sub> x<sub>4</sub> + a<sub>1,5</sub>  x<sub>5</sub> + a<sub>1,6</sub> x<sub>6</sub>

y<sub>PC2</sub> = a<sub>2,1</sub> x<sub>1</sub> + a<sub>2,2</sub> x<sub>2</sub> +  a<sub>2,3</sub> x<sub>3</sub> + a<sub>2,4</sub> x<sub>4</sub> + a<sub>2,5</sub>  x<sub>5</sub> + a<sub>2,6</sub> x<sub>6</sub>

y<sub>PC3</sub> = a<sub>3,1</sub> x<sub>1</sub> + a<sub>3,2</sub> x<sub>2</sub> +  a<sub>3,3</sub> x<sub>3</sub> + a<sub>3,4</sub> x<sub>4</sub> + a<sub>3,5</sub>  x<sub>5</sub> + a<sub>3,6</sub> x<sub>6</sub>

...

y<sub>PC6</sub> = a<sub>6,1</sub> x<sub>1</sub> + a<sub>6,2</sub> x<sub>2</sub> +  a<sub>6,3</sub> x<sub>3</sub> + a<sub>6,4</sub> x<sub>4</sub> + a<sub>6,5</sub>  x<sub>5</sub> + a<sub>6,6</sub> x<sub>6</sub>

ここで、係数 a<sub>ij</sub> (i = 1...6, j = 1...6) を「固有ベクトル」といい、主成分得点に対する観測値の影響度を表します。説明変数の個数が p の場合、主成分PCは p 個算出されます。

主成分分析では、固有値（＝主成分得点の分散）が大きい主成分得点ほど重要と判断します。

ちなみに、主成分分析は「教師なし機械学習」の一種とされ、データ自身が持つ構造を明らかにします。詳しくは <a href="https://qiita.com/maskot1977/items/eb695b516fd320aad495">主成分分析をExcelで理解する</a> や <a href="https://qiita.com/maskot1977/items/082557fcda78c4cdb41f">主成分分析を Python で理解する</a> などを参照のこと。


```python
from sklearn.decomposition import PCA #主成分分析器
```


```python
#主成分分析の実行
pca = PCA()
pca.fit(df.iloc[:, 5:11])
# データを主成分空間に写像 = 次元圧縮
feature = pca.transform(df.iloc[:, 5:11])
# 第一主成分と第二主成分でプロットする
plt.figure(figsize=(8, 8))
plt.scatter(feature[:, 0], feature[:, 1], alpha=0.8)
plt.xlabel('PC1')
plt.ylabel('PC2')
plt.grid()
plt.show()
```

![output_33_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/4658f0df-42fb-b64b-1f2e-519b2be520d0.png)


このプロットがどの程度の量の情報を表しているでしょうか。主成分分析した時は、累積寄与率を確認することが必要です。


```python
# 累積寄与率を図示する
import matplotlib.ticker as ticker
import numpy as np
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 ratio")
plt.grid()
plt.show()
```

![output_35_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/6d6680bb-452e-2eba-679b-5ade2cd0210a.png)

第一主成分と第二主成分で累積寄与率が７０％弱。けっこう情報損失していますが、これで何が言えるか考えてみましょう。主成分分析のプロットを属性で色分けしてみます。


```python
#主成分分析の実行
pca = PCA()
pca.fit(df.iloc[:, 5:11])
# データを主成分空間に写像 = 次元圧縮
feature = pca.transform(df.iloc[:, 5:11])
# 第一主成分と第二主成分でプロットする
plt.figure(figsize=(8, 8))
for type1 in type1s:
    plt.scatter(feature[df['Type 1'] == type1, 0], feature[df['Type 1'] == type1, 1], alpha=0.8, label=type1)
plt.xlabel('PC1')
plt.ylabel('PC2')
plt.legend(loc = 'upper right',
          bbox_to_anchor = (0.7, 0.7, 0.5, 0.1),
          borderaxespad = 0.0)
plt.grid()
plt.show()
```

![output_37_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/d8a8f282-ec5f-2619-7207-9535462c6661.png)


んー、主成分と属性は特に関係なさそうですね。では、世代（generation）はどうでしょうか。


```python
#主成分分析の実行
pca = PCA()
pca.fit(df.iloc[:, 5:11])
# データを主成分空間に写像 = 次元圧縮
feature = pca.transform(df.iloc[:, 5:11])
# 第一主成分と第二主成分でプロットする
plt.figure(figsize=(8, 8))
for generation in range(0, 7):
    plt.scatter(feature[df['Generation'] == generation, 0], feature[df['Generation'] == generation, 1], alpha=0.8, label=generation)
plt.xlabel('PC1')
plt.ylabel('PC2')
plt.legend(loc = 'upper right',
          bbox_to_anchor = (0.7, 0.7, 0.5, 0.1),
          borderaxespad = 0.0)
plt.grid()
plt.show()
```

![output_39_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/5d25722e-35b8-593d-a54e-9844d18ee848.png)


これも特に関係なさそうです。では Legendary （伝説のポケモンかどうか）は？


```python
#主成分分析の実行
pca = PCA()
pca.fit(df.iloc[:, 5:11])
# データを主成分空間に写像 = 次元圧縮
feature = pca.transform(df.iloc[:, 5:11])
# 第一主成分と第二主成分でプロットする
plt.figure(figsize=(8, 8))
for binary in [True, False]:
    plt.scatter(feature[df['Legendary'] == binary, 0], feature[df['Legendary'] == binary, 1], alpha=0.8, label=binary)
plt.xlabel('PC1')
plt.ylabel('PC2')
plt.legend(loc = 'upper right',
          bbox_to_anchor = (0.7, 0.7, 0.5, 0.1),
          borderaxespad = 0.0)
plt.grid()
plt.show()
```

![output_41_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/144b111d-bdf2-935f-c584-694d5e6615ad.png)


第一主成分（PC1）が 50 のところで、完全ではありませんが、伝説のポケモンになれるどうかの区別ができそうです！

では、第一主成分（PC1）がどの説明変数（パラメータ）からどの程度寄与されているかローディングプロットで図示してみましょう。


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

![output_43_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/57128129-b181-7fce-0f31-7f0b87230e58.png)


第一主成分（PC1）が「伝説のポケモンになれるかどうかの指標」だとして、それは「Sp. Atk」（会心の一撃の強さ？かと思ってたけど「特殊攻撃力」だそうです）と「Attack」（攻撃力）の寄与が大きいようです。

第二主成分（PC1）は、Defence（防御力）と Speed （スピード）が正負逆の寄与をしています。これは

__「当たらなければ、どうということはない！」__

という名言で有名な、通常の３倍速い赤い彗星ことシャア・アズナブル的な戦術を取るかどうかという流儀の違いでしょうか。

# 因子分析

主成分分析とは似て非なる手法として「因子分析」(Factor Analysis) があります。

主成分分析(PCA)では、説明変数に対して重み行列（固有ベクトル）a を線形結合した「主成分」 y<sub>PC1</sub>を合成しました。ここで、主成分は、説明変数と同じ数だけ定義します。

y<sub>PC1</sub> = a<sub>1,1</sub> x<sub>1</sub> + a<sub>1,2</sub>  x<sub>2</sub> +  a<sub>1,3</sub> x<sub>3</sub> + a<sub>1,4</sub> x<sub>4</sub> + a<sub>1,5</sub> + ...

因子分析では、説明変数（観測変数）x が「因子」(factor) という潜在変数から合成されるという考え方に基づき、その因子得点 f と重み行列（因子負荷） w 、そして独自因子 e を特定します（主成分分析に独自因子という考え方はありません）。

x<sub>1</sub> = w<sub>1,1</sub> f<sub>1</sub> + w<sub>1,2</sub> f<sub>2</sub> +  e<sub>1</sub>

x<sub>2</sub> = w<sub>2,1</sub> f<sub>1</sub> + w<sub>2,2</sub> f<sub>2</sub> +  e<sub>2</sub>

x<sub>3</sub> = w<sub>3,1</sub> f<sub>1</sub> + w<sub>3,2</sub> f<sub>2</sub> +  e<sub>3</sub>

x<sub>4</sub> = w<sub>4,1</sub> f<sub>1</sub> + w<sub>4,2</sub> f<sub>2</sub> +  e<sub>4</sub>

x<sub>5</sub> = w<sub>5,1</sub> f<sub>1</sub> + w<sub>5,2</sub> f<sub>2</sub> +  e<sub>5</sub>

x<sub>6</sub> = w<sub>6,1</sub> f<sub>1</sub> + w<sub>6,2</sub> f<sub>2</sub> +  e<sub>6</sub>

因子得点 f は、各個体（サンプル）が独自に持つ潜在変数です。因子得点と因子負荷の線形和（w<sub>1,1</sub> f<sub>1</sub> + w<sub>1,2</sub> f<sub>2</sub> など）を「共通因子」と呼び、観測変数独自の「独自因子」e と足し合わせることで「観測変数」として観測できるという考え方です。因子の個数は説明変数よりも小さな個数を使うのが普通で、あらかじめ決めておく必要があります。

（ただし、共通因子や因子などの用語は、調べてみた限り異なる人が異なる定義をしているように見えますので、大変紛らわしいです。私の説明のほうが間違っている可能性もありますのでその際はご容赦ください。）

詳しくは <a href="https://qiita.com/maskot1977/items/ab6d038d622ecbb0730d">因子分析をExcelで理解する</a> を参照のこと。


```python
from sklearn.decomposition import FactorAnalysis
fa = FactorAnalysis(n_components=2, max_iter=500)
factors = fa.fit_transform(df.iloc[:, 5:11])
```


```python
plt.figure(figsize=(8, 8))
for binary in [True, False]:
    plt.scatter(factors[df['Legendary'] == binary, 0], factors[df['Legendary'] == binary, 1], alpha=0.8, label=binary)
plt.xlabel("Factor 1")
plt.ylabel("Factor 2")
plt.legend(loc = 'upper right',
          bbox_to_anchor = (0.7, 0.7, 0.5, 0.1),
          borderaxespad = 0.0)
plt.grid()
plt.show()
```

![output_47_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/50517548-f2e7-d8db-99b0-6742e5751912.png)


伝説のポケモンになれるかどうかは、因子１と因子２の和が一定以上になるかどうかで決まりそうですが、因子２の大きい方にやや偏っているようです。ではその因子２や因子１はどのパラメータに寄与しているでしょうか？


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

![output_49_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/3278591c-f4b3-1e71-13fd-760fcf9a2e41.png)


因子２は「Sp. Atk」（特殊攻撃力）に、因子１は Defense （防御力）に大きく寄与しているようです。

# 行列の標準化

次の処理に用いるため、データの標準化を行っておきましょう。平均値で引いてから標準偏差で割ります。 axis=0 （列ごとの処理）と axis=1（行ごとの処理）の違いに注意しましょう。詳しくは <a href="https://qiita.com/maskot1977/items/fb36c861aee02ea18755">Pandas を用いた演算</a> を参照のこと。


```python
# 行列の正規化
dfs = df.iloc[:, 5:11].apply(lambda x: (x-x.mean())/x.std(), axis=0)
```

# 階層的クラスタリング

階層的クラスタリングについては <a href="https://www.slideshare.net/maskot3/ss-121402523">階層的クラスタリング入門の入門</a> などを参照のこと。これも「教師なし機械学習」の一種です。

クラスタリングには色んな metric（「距離」の定義）と method （結合方法）があるので、その中からそれぞれ一つずつを選択します。


```python
# metric は色々あるので、ケースバイケースでどれかひとつ好きなものを選ぶ。
# method も色々あるので、ケースバイケースでどれかひとつ好きなものを選ぶ。
from scipy.cluster.hierarchy import linkage, dendrogram
result1 = linkage(dfs, 
                  #metric = 'braycurtis', 
                  #metric = 'canberra', 
                  #metric = 'chebyshev', 
                  #metric = 'cityblock', 
                  #metric = 'correlation',
                  #metric = 'cosine', 
                  metric = 'euclidean', 
                  #metric = 'hamming', 
                  #metric = 'jaccard', 
                  #method= 'single')
                  method = 'average')
                  #method= 'complete')
                  #method='weighted')
plt.figure(figsize=(8, 128))
dendrogram(result1, orientation='right', labels=list(df['Name']), color_threshold=2)
plt.title("Dedrogram")
plt.xlabel("Threshold")
plt.grid()
plt.show()
```

![output_54_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/685a6eb5-3d36-b1b9-ac0f-929642dbf97d.png)

## 指定したクラスタ数になるよう分割

上記の結果をもとに、指定したクラスタ数でクラスタ（特徴のよく似たグループ）を作りましょう。詳細は <a href="https://qiita.com/maskot1977/items/a35ac2fdc2c7448ee526">階層的クラスタリングとシルエット係数</a> を参照のこと。


```python
# 指定したクラスタ数でクラスタを得る関数を作る。
def get_cluster_by_number(result, number):
    output_clusters = []
    x_result, y_result = result.shape
    n_clusters = x_result + 1
    cluster_id = x_result + 1
    father_of = {}
    x1 = []
    y1 = []
    x2 = []
    y2 = []
    for i in range(len(result) - 1):
        n1 = int(result[i][0])
        n2 = int(result[i][1])
        val = result[i][2]
        n_clusters -= 1
        if n_clusters >= number:
            father_of[n1] = cluster_id
            father_of[n2] = cluster_id

        cluster_id += 1

    cluster_dict = {}
    for n in range(x_result + 1):
        if n not in father_of:
            output_clusters.append([n])
            continue

        n2 = n
        m = False
        while n2 in father_of:
            m = father_of[n2]
            #print [n2, m]
            n2 = m

        if m not in cluster_dict:
            cluster_dict.update({m:[]})
        cluster_dict[m].append(n)

    output_clusters += cluster_dict.values()

    output_cluster_id = 0
    output_cluster_ids = [0] * (x_result + 1)
    for cluster in sorted(output_clusters):
        for i in cluster:
            output_cluster_ids[i] = output_cluster_id
        output_cluster_id += 1

    return output_cluster_ids
```

たとえば 50 個のクラスタに分割したいと思います。


```python
clusterIDs = get_cluster_by_number(result1, 50)
print(clusterIDs)
```

    [0, 0, 1, 2, 0, 3, 4, 4, 2, 0, 0, 1, 2, 0, 0, 3, 0, 0, 3, 5, 0, 0, 3, 4, 0, 3, 0, 3, 0, 3, 0, 3, 0, 0, 0, 0, 3, 0, 0, 3, 0, 1, 0, 3, 6, 7, 0, 3, 0, 0, 1, 0, 0, 0, 3, 8, 9, 0, 3, 0, 3, 0, 3, 0, 4, 0, 0, 3, 10, 10, 4, 11, 0, 0, 12, 0, 0, 12, 13, 1, 14, 14, 15, 3, 3, 0, 1, 16, 14, 17, 0, 0, 3, 0, 1, 0, 12, 14, 18, 10, 10, 4, 11, 19, 0, 1, 14, 12, 10, 9, 14, 12, 14, 0, 20, 20, 1, 14, 17, 14, 15, 21, 17, 22, 22, 14, 17, 0, 3, 10, 3, 13, 3, 4, 3, 3, 12, 23, 3, 8, 22, 24, 1, 0, 0, 1, 4, 20, 0, 14, 17, 14, 12, 3, 5, 25, 1, 4, 4, 0, 3, 24, 4, 26, 26, 1, 0, 0, 1, 0, 3, 4, 0, 0, 3, 0, 3, 0, 1, 0, 13, 0, 0, 3, 0, 1, 8, 0, 6, 14, 0, 0, 3, 0, 0, 1, 27, 1, 0, 1, 14, 1, 0, 0, 3, 0, 0, 1, 3, 0, 12, 4, 28, 3, 1, 3, 0, 29, 3, 14, 15, 1, 30, 31, 31, 0, 12, 3, 12, 24, 32, 22, 23, 9, 0, 12, 0, 33, 0, 12, 0, 0, 12, 0, 13, 30, 0, 3, 4, 1, 0, 15, 1, 3, 0, 0, 20, 10, 3, 3, 22, 21, 4, 22, 1, 0, 0, 24, 24, 28, 2, 1, 0, 3, 3, 4, 0, 0, 4, 4, 0, 0, 12, 24, 0, 3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 3, 0, 9, 0, 17, 0, 0, 4, 2, 0, 0, 0, 12, 0, 3, 34, 14, 9, 35, 0, 0, 3, 0, 25, 0, 36, 0, 0, 0, 33, 0, 33, 14, 15, 31, 31, 0, 3, 3, 0, 3, 4, 3, 3, 3, 3, 3, 0, 1, 37, 4, 4, 7, 7, 0, 12, 27, 15, 0, 1, 0, 35, 0, 3, 0, 12, 0, 1, 1, 3, 12, 3, 3, 0, 3, 0, 12, 0, 1, 0, 1, 0, 12, 8, 1, 3, 1, 0, 12, 20, 36, 33, 1, 3, 12, 4, 0, 0, 3, 4, 0, 1, 1, 14, 17, 17, 15, 10, 0, 0, 4, 24, 0, 0, 24, 24, 31, 38, 39, 1, 2, 4, 2, 2, 40, 24, 41, 42, 26, 1, 43, 43, 39, 44, 0, 0, 12, 0, 3, 3, 0, 0, 1, 0, 0, 3, 0, 3, 0, 3, 0, 0, 4, 0, 4, 37, 45, 36, 39, 0, 0, 0, 0, 0, 0, 1, 3, 0, 3, 0, 3, 0, 1, 3, 0, 7, 0, 3, 5, 4, 12, 0, 3, 0, 0, 3, 36, 33, 14, 13, 6, 3, 33, 0, 3, 22, 24, 25, 0, 4, 4, 0, 15, 14, 30, 0, 3, 12, 0, 3, 13, 0, 3, 27, 5, 17, 1, 15, 15, 4, 4, 1, 3, 30, 17, 30, 22, 4, 20, 23, 39, 33, 3, 3, 17, 17, 17, 17, 17, 28, 1, 4, 2, 2, 2, 24, 42, 42, 28, 3, 1, 4, 1, 4, 42, 1, 0, 3, 3, 0, 3, 12, 0, 0, 12, 0, 3, 0, 0, 22, 0, 3, 0, 3, 0, 3, 0, 3, 0, 1, 0, 0, 3, 0, 3, 14, 14, 15, 0, 3, 0, 22, 1, 28, 0, 12, 15, 0, 0, 3, 25, 22, 0, 0, 3, 0, 14, 3, 0, 3, 0, 3, 3, 0, 0, 22, 0, 22, 46, 12, 0, 15, 0, 33, 3, 14, 33, 14, 15, 12, 4, 0, 3, 0, 4, 0, 3, 0, 0, 1, 47, 47, 1, 0, 3, 0, 0, 1, 0, 3, 3, 0, 15, 0, 1, 0, 1, 7, 0, 3, 36, 33, 0, 0, 30, 0, 0, 12, 0, 1, 0, 0, 17, 0, 12, 12, 0, 12, 13, 14, 9, 1, 0, 4, 12, 0, 12, 0, 12, 12, 0, 22, 0, 22, 12, 30, 0, 0, 4, 0, 4, 30, 22, 1, 4, 3, 4, 4, 2, 24, 4, 4, 42, 24, 42, 4, 4, 2, 22, 4, 0, 0, 15, 0, 3, 4, 0, 3, 3, 0, 3, 0, 0, 3, 0, 0, 3, 0, 3, 0, 0, 2, 0, 1, 0, 12, 3, 0, 3, 3, 14, 15, 48, 39, 0, 1, 0, 3, 0, 3, 0, 15, 0, 1, 0, 1, 0, 4, 0, 15, 0, 1, 1, 3, 3, 39, 0, 1, 2, 3, 0, 12, 0, 0, 0, 0, 30, 30, 15, 15, 14, 31, 0, 3, 42, 42, 1, 39, 49, 2, 40, 2]


クラスタへの分配のされ方は次のようになりました。


```python
plt.hist(clusterIDs, bins=50)
plt.grid()
plt.show()
```

![output_60_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/56600d31-8b8e-fb93-8f78-90c4f1eb9f38.png)


## レーダーチャートによるクラスタの図示

<a href="https://qiita.com/1007/items/80406e098a4212571b2e">Matplotlibでレーダーチャートを描く（16行）</a> を参考に、各クラスターに分類されたポケモンの特徴を可視化しましょう。


```python
for i in range(max(clusterIDs) + 1):
    cluster = []
    for j, k in enumerate(clusterIDs):
        if i == k:
            cluster.append(j)
    fig = plt.figure()
    print("Cluster {}: {} samples".format(i + 1, len(cluster)))
    for j in cluster:
        labels = list(df.columns[5:11])
        values = list(df.iloc[j, 5:11])
        angles = np.linspace(0, 2 * np.pi, len(labels) + 1, endpoint=True)
        values = np.concatenate((values, [values[0]]))  # 閉じた多角形にする
        ax = fig.add_subplot(111, polar=True)
        ax.plot(angles, values, 'o-', label=df.iloc[j, :]['Name'] + " (" + df.iloc[j, :]['Type 1'] + ")")  # 外枠
        #ax.fill(angles, values, alpha=0.25)  # 塗りつぶし
        ax.set_thetagrids(angles[:-1] * 180 / np.pi, labels)  # 軸ラベル
        ax.set_rlim(0 ,250)
    plt.legend( loc = 'center right',
          bbox_to_anchor = (1.5, 0.5, 0.5, 0.1),
          borderaxespad = 0.0)
    plt.show()
```

Cluster 1: 264 samples

![output_62_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/e759db5b-bd38-5fcb-2872-30bcc4772664.png)

Cluster 2: 68 samples


![output_62_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/dfffbf96-bd07-617e-a3c0-3867c851afeb.png)

Cluster 3: 17 samples


![output_62_6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/e74ca8bc-f168-99dd-aaa5-8cb416d6f85b.png)

Cluster 4: 128 samples


![output_62_8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/569b5beb-9919-2d5e-719b-c4f10a2a1f46.png)

Cluster 5: 52 samples


![output_62_10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/eca7f08f-a2a6-4d46-4bfd-e243d0bc7c9e.png)


Cluster 6: 4 samples


![output_62_12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/871d4fa8-f158-1b0b-4913-ced05bd0584d.png)

Cluster 7: 3 samples


![output_62_14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/6eff2548-1732-f2cc-f772-14e9dcbac566.png)

Cluster 8: 5 samples


![output_62_16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/a54e0483-cbaf-868c-400c-6e096e2f08dc.png)

Cluster 9: 4 samples


![output_62_18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/f0806dea-dc85-e9ef-b114-42ff4c76b97c.png)

Cluster 10: 6 samples


![output_62_20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/823bd03e-0102-7bee-7bb0-378dbd516f24.png)

Cluster 11: 8 samples


![output_62_22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/6d9f17c5-4491-dae8-1f8e-87d8c654706c.png)


Cluster 12: 2 samples


![output_62_24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/10ce30f5-2c3c-8e31-9f0d-9eed7f0c81a4.png)


Cluster 13: 41 samples


![output_62_26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/9a7701c6-eb55-9bba-8bf4-a831daeed544.png)


Cluster 14: 7 samples


![output_62_28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/8846749c-90c0-426a-9b22-d1ae244edd0e.png)

Cluster 15: 28 samples


![output_62_30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/b39f341f-e695-5bfd-3aed-e0e37a7bf916.png)


Cluster 16: 21 samples


![output_62_32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/cd5f8caa-d056-f9f0-e07e-38aa4baa4124.png)


Cluster 17: 1 samples


![output_62_34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/210226cf-7ba1-1dbe-eeaa-bb21de416ab9.png)


Cluster 18: 16 samples


![output_62_36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/81022927-b72a-4fdf-af71-7dfa6892bc92.png)


Cluster 19: 1 samples


![output_62_38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/c48610f5-81f7-44ff-6000-6fe7209fce77.png)


Cluster 20: 1 samples


![output_62_40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/82bfe42e-bf0d-3b8f-7ddc-6b14f98eff21.png)


Cluster 21: 6 samples


![output_62_42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/1e13b07a-29ea-24e2-84ea-a193f821a2ab.png)


Cluster 22: 2 samples


![output_62_44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/decd1474-dfcd-d492-5d92-4e93f7cd4871.png)


Cluster 23: 17 samples


![output_62_46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/5eece632-cab5-acd7-ed20-27de8ba9c85a.png)


Cluster 24: 3 samples


![output_62_48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/9b5177b4-4b42-6ccb-3788-c1af32a04d31.png)


Cluster 25: 14 samples


![output_62_50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/5368a723-aabc-bc2b-6a08-3b577c51d4dc.png)


Cluster 26: 4 samples


![output_62_52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/90d73241-a62c-bd60-25ca-caabb5c113d2.png)


Cluster 27: 3 samples


![output_62_54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/9d3f3afb-8060-ea55-3a14-b8d709ede77e.png)


Cluster 28: 3 samples


![output_62_56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/6d82f059-fa52-d931-ed3a-45c59642cea2.png)


Cluster 29: 5 samples


![output_62_58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/bc1a0b45-7d02-1088-1be4-0c4b51e78dd0.png)


Cluster 30: 1 samples


![output_62_60.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/1cbc056b-ec7c-02f2-1b88-b5776e7dc828.png)


Cluster 31: 10 samples


![output_62_62.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/d9209b4f-0051-7c95-dfdf-7e48e31e315d.png)


Cluster 32: 6 samples


![output_62_64.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/073c9d89-7797-d54a-cab4-88044c884c54.png)


Cluster 33: 1 samples


![output_62_66.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/f875b006-ad04-53fc-a75f-77a0b2098d7d.png)


Cluster 34: 10 samples


![output_62_68.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/e8820923-f6be-7ee4-a870-b2bc120ff908.png)


Cluster 35: 1 samples


![output_62_70.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/6e05ceaf-c56e-da17-2623-1b5ee894eea0.png)


Cluster 36: 2 samples


![output_62_72.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/ae90a6c3-2bed-5e34-f893-33412fb0f378.png)


Cluster 37: 5 samples


![output_62_74.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/044f8eeb-6769-9f97-7213-53e5ccb717c4.png)


Cluster 38: 2 samples


![output_62_76.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/35550569-fdd2-896b-6ebb-70a099b2a655.png)


Cluster 39: 1 samples


![output_62_78.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/1eeedab4-e31d-8a91-ce35-3c6eeb33f77b.png)


Cluster 40: 7 samples


![output_62_80.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/81000849-1a08-d240-e82e-7e920fa8fe97.png)


Cluster 41: 2 samples


![output_62_82.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/b794a86b-6ff4-7ca9-3311-2a4bc37a2a0a.png)


Cluster 42: 1 samples


![output_62_84.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/9c0a4459-f8dd-b16c-d7f3-5088973a0a52.png)


Cluster 43: 8 samples


![output_62_86.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/3554e187-1981-9958-0d2c-a4314045f138.png)


Cluster 44: 2 samples


![output_62_88.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/835d4668-cbdd-9de1-f64d-e3ff76f3d43f.png)


Cluster 45: 1 samples


![output_62_90.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/33224e7b-566b-e632-3586-9aa453c972ef.png)


Cluster 46: 1 samples


![output_62_92.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/1f26ba77-9571-aa57-83cd-cef7aa76378e.png)


Cluster 47: 1 samples


![output_62_94.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/06caceeb-4947-1255-1d34-3f56b2e1db49.png)


Cluster 48: 2 samples


![output_62_96.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/2b940c53-bfda-0658-c102-bbaf7c3d6ca5.png)


Cluster 49: 1 samples


![output_62_98.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/6ad7fb7c-2088-8e06-d6a2-0e0ea82bfedd.png)


Cluster 50: 1 samples


![output_62_100.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/706c0b65-9b75-63de-15ea-c9d72409a458.png)


どうやら、特殊なパラメータ配分を持つポケモンはいるものの、属性（Type 1）とパラメータ（HPなど）との間には、特別関係があるわけではなさそうです。

# 回帰

今度は「回帰」をしてみましょう。回帰は「教師あり機械学習」の一種で、説明変数 X から目的変数 y を予測する手法のうち、目的変数 y が連続値のものをいいます。ここで、説明変数 X と目的変数 y との関係を「学習」するのですが、目的変数 y のことを「教師」と呼ぶことがあります。

まずは 説明変数 X と目的変数 y を決めましょう。ここでは、HPなどのパラメータを説明変数 X, 総合値（Total）を目的変数 y とします。


```python
X = df.iloc[:, 5:11]
y = df['Total']
```

## 線形重回帰

回帰のうち最も基本的なものが「線形回帰」で、そのうち説明変数が複数あるものを「線形重回帰」と呼びます。詳しくは <a href="https://qiita.com/maskot1977/items/7b3c11fffc3ba436d8be">線形単回帰を Python で理解する</a> を参照のこと。


```python
from sklearn import linear_model
regr = linear_model.LinearRegression()
regr.fit(X, y) # 予測モデルを作成

print("回帰係数= ", regr.coef_)
print("切片= ", regr.intercept_)
print("決定係数= ", regr.score(X, y))
```

    回帰係数=  [1. 1. 1. 1. 1. 1.]
    切片=  5.684341886080802e-14
    決定係数=  1.0


ありゃ...回帰係数が全部 1 ... 「Total」は各パラメータの単純な和でしたか...そういえば

__Total__: Sum of Attack, Sp. Atk, Defense, Sp. Def, Speed and HP

って書いてあったわ。

改めてデータ構造を見直してみて、


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

<img width="642" alt="スクリーンショット 2019-06-14 11.50.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/d0661be6-fe01-b17f-f0df-693ba39779cf.png">


```python
df.columns[[5, 6, 7, 10]]
```




    Index(['HP', 'Attack', 'Defense', 'Speed'], dtype='object')



この４つを説明変数 X とし、"Sp. Atk" を予測してみましょう。すると問題が良い感じに難しくなるはず。


```python
X = df.iloc[:, [5, 6, 7, 10]]
y = df['Sp. Atk']
```


```python
from sklearn import linear_model
regr = linear_model.LinearRegression()
regr.fit(X, y) # 予測モデルを作成

print("回帰係数= ", regr.coef_)
print("切片= ", regr.intercept_)
print("決定係数= ", regr.score(X, y))
```

    回帰係数=  [0.28468407 0.10004721 0.12673883 0.4439368 ]
    切片=  5.529675896993538
    決定係数=  0.3333279772212076


つまり、

__'Sp. Atk'__ = 0.28 * __HP__ + 0.10 * __Attack__ + 0.13 * __Defence__ + 0.44 * __Speed__ + 5.5

という関係にあるわけですね。ただし、決定係数が大変小さいので、信頼できるモデルとは言えません。

## クロスバリデーション（交差検証）

機械学習ではその性能評価をするために、既知データを訓練データ（教師データ、教師セットともいいます）とテストデータ（テストセットともいいます）に分割します。訓練データを用いて訓練（学習）して予測モデルを構築し、その予測モデル構築に用いなかったテストデータをどのくらい正しく予測できるかということで性能評価を行ないます。そのような評価方法を「交差検証」(cross-validation)と呼びます。ここでは、

* 訓練データ（全データの６０％）
  * X_train : 訓練データの説明変数
  * y_train : 訓練データの目的変数
* テストデータ（全データの４０％）
  * X_test : テストデータの説明変数
  * y_test : テストデータの目的変数

とし、X_train と y_train の関係を学習して X_test から y_test を予測することを目指します。もしも、訓練データでは良い性能を示しているように見えても、学習に用いなかったテストデータでは性能が低い場合、そのモデルは「過学習した」と言います。詳しくは <a href="https://www.slideshare.net/maskot3/ss-121401969">機械学習入門の入門</a> を参照のこと。


```python
#from sklearn.cross_validation import train_test_split # 訓練データとテストデータに分割
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.4) # 訓練データ・テストデータへのランダムな分割
```


```python
from sklearn import linear_model
regr = linear_model.LinearRegression()
regr.fit(X_train, y_train) # 予測モデルを作成

print("回帰係数= ", regr.coef_)
print("切片= ", regr.intercept_)
print("決定係数(train)= ", regr.score(X_train, y_train))
print("決定係数(test)= ", regr.score(X_test, y_test))
```

    回帰係数=  [0.28050284 0.13629344 0.09994709 0.48036096]
    切片=  4.510621382128264
    決定係数(train)=  0.3494685274982846
    決定係数(test)=  0.2558419802439882


訓練データ・テストデータへの分割はランダムに行われるため、上記の値は計算のたびに変わります。

### 標準回帰係数

回帰式を求めるなら上記のようにすれば良いわけですが、説明変数・目的変数を標準化してから回帰することで「標準回帰係数」が求められ、これが「変数の重要度」の指標になります。


```python
Xs = X.apply(lambda x: (x-x.mean())/x.std(), axis=0)
ys = list(pd.DataFrame(y).apply(lambda x: (x-x.mean())/x.std()).values.reshape(len(y),))
```


```python
from sklearn import linear_model
regr = linear_model.LinearRegression()

regr.fit(Xs, ys) # 予測モデルを作成

print("標準回帰係数= ", regr.coef_)
print("切片= ", regr.intercept_)
print("決定係数= ", regr.score(Xs, ys))
```

    標準回帰係数=  [0.22215171 0.0992372  0.12077883 0.39425762]
    切片=  3.2105349393792207e-16
    決定係数=  0.33332797722120766


得られた標準回帰係数を図示してみると


```python
pd.DataFrame(regr.coef_, index=list(df.columns[[5, 6, 7, 10]])).sort_values(0, ascending=False).style.bar(subset=[0])
```

<img width="167" alt="スクリーンショット 2019-06-14 11.51.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/0c90d65d-76da-e495-3785-1f2b17ce245b.png">


「Sp. Atk」（特殊攻撃力）を予測するにあたり、Speed（スピード）の重要度が大きいようです。

## 拡張型数量化I類

数量化理論とは、数値ではない「カテゴリカルデータ」と呼ばれるデータをいかに統計学の世界に招き入れるかという理論で、数量化I類、数量化II類などが有名です。

重回帰分析などの回帰分析は、数値データを説明変数とし、数値データを目的変数として予測します。一方で、数値ではないカテゴリカルデータを説明変数とし、数値データを目的変数として予測するのが数量化I類です。説明変数に数値データとカテゴリカルが混在している場合は拡張型数量化I類と呼ばれます。

詳しくは <a href="https://qiita.com/maskot1977/items/6235aaad28b1ad8f1713">数量化理論をPythonで理解する</a> を参照のこと。

### カテゴリカルデータをダミー変数に変換

pandas.get_dummies() を用いて、カテゴリカルデータをダミー変数に変換します。ダミー変数とは、そのカテゴリーに属すれば１、属さなければ０の変数です。dummy_na=True を指定すると、データが NaN（欠損値） の場合に１、欠損でなければ０とします。

重回帰分析などでは、カテゴリーの数がN個ある場合、N個のダミー変数を作ると予測できないため、どれか1個の変数を除外します。scikit-learnの重回帰分析 LinearRegression() では、この問題を回避する設計にしているようで、N個のダミー変数を作成しても動作します。

なお、pandas.get_dummies(drop_first=True) とすると、ダミー変数を作成するときに最初のカテゴリーを無視します。


```python
df2 = pd.get_dummies(df.iloc[:, 2:], dummy_na=True)
df2.head()
```

<img width="849" alt="スクリーンショット 2019-06-14 11.52.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/8a380d45-fb9e-5d28-0dde-77c3c518b6e9.png">



```python
X = df2
del X['Total']
del X['Sp. Atk']
del X['Sp. Def']
del X['Legendary']
X.head()
```

<img width="854" alt="スクリーンショット 2019-06-14 11.53.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/1b55c443-dfe7-e5ff-88cb-496c0391a805.png">



```python
#from sklearn.cross_validation import train_test_split # 訓練データとテストデータに分割
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.4) # 訓練データ・テストデータへのランダムな分割
```


```python
from sklearn import linear_model
regr = linear_model.LinearRegression()
regr.fit(X_train, y_train) # 予測モデルを作成

print("回帰係数= ", regr.coef_)
print("切片= ", regr.intercept_)
print("決定係数(train)= ", regr.score(X_train, y_train))
print("決定係数(test)= ", regr.score(X_test, y_test))
```

    回帰係数=  [ 2.28431738e-01  2.97742060e-01  8.02614939e-02  2.20997067e-01
     -1.55704518e-01 -1.47132780e+01 -5.84090849e+00  2.19195137e+00
      1.77819922e+01  1.91024750e+01 -2.45614311e+01  1.85155570e+01
      7.95924485e+00  9.10518038e+00  3.54309623e+00 -2.24760486e+01
      8.41016188e+00 -1.78568717e+01 -2.51439443e+00  2.62609157e+01
     -1.41838440e+01 -1.43994552e+01  3.67565689e+00 -1.61076024e-15
     -5.36512027e+00 -1.06042187e+01  1.22074186e+01  4.27173718e+00
      7.26562566e+00 -2.00570257e+01  2.25619608e+01 -4.07020702e+00
      3.76104637e+00 -7.93072478e+00 -1.15056412e+01  1.91256670e+01
     -3.63271870e+00  6.58290356e+00  1.54416323e+01 -1.33194463e+01
     -1.09096992e+01  3.44875964e+00 -7.27194918e+00]
    切片=  17.69492260426813
    決定係数(train)=  0.5716379265230409
    決定係数(test)=  0.4658252989421211


変数を増やすことで、いくらか性能が上がったようですね。

## ランダムフォレストによる回帰

<a href="https://scikit-learn.org/stable/">Scikit-learn</a> というライブラリには、線形重回帰以外にも様々な回帰手法が実装されています。今回はその中のひとつ、ランダムフォレストを使った回帰をしてみましょう。


```python
from sklearn.ensemble import RandomForestRegressor
regr = RandomForestRegressor(max_depth=2, random_state=0, n_estimators=100)
regr.fit(X_train, y_train)
print("決定係数(train)= ", regr.score(X_train, y_train))
print("決定係数(test)= ", regr.score(X_test, y_test))
```

    決定係数(train)=  0.37839205866915593
    決定係数(test)=  0.3265735023596227


ランダムフォレストの興味深い点は、feature importance という指標で、パラメータの重要性を相対的に評価できることです。


```python
regr.feature_importances_
```




    array([0.3960066 , 0.04625405, 0.05236526, 0.42465029, 0.        ,
           0.00299188, 0.        , 0.00357449, 0.00097514, 0.        ,
           0.        , 0.        , 0.        , 0.004711  , 0.        ,
           0.        , 0.        , 0.05131166, 0.        , 0.00934274,
           0.        , 0.        , 0.        , 0.        , 0.        ,
           0.        , 0.00412505, 0.        , 0.00098141, 0.        ,
           0.        , 0.        , 0.        , 0.        , 0.        ,
           0.00122454, 0.        , 0.00148591, 0.        , 0.        ,
           0.        , 0.        , 0.        ])



ほとんどの feature importance は０となりました。上位１０個のパラメータを並べてみましょう。


```python
pd.DataFrame(regr.feature_importances_, index=list(X.columns)).sort_values(0, ascending=False).head(10).style.bar(subset=[0])
```

<img width="196" alt="スクリーンショット 2019-06-14 11.54.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/88c51659-ef83-55e1-f09f-0c2dcc9867b3.png">


Speed、HP、Defence の順に重要であるということは線形重回帰の結果と同じですが、Type 1_Normal や Type 1_Psychic などが重要なパラメータとしてリストアップされています。

# ２クラス分類

今度は、パラメータ（HPなど）から「伝説のポケモンかどうか」を予測するような「２クラス分類」問題を解いてみましょう。

目的変数が連続値の場合は「回帰」と呼ばれますが、目的変数が０か１かなどの離散値（カテゴリカルデータ）の場合は「分類」と呼ばれます。その中で、数値ではないカテゴリカルデータを説明変数とするものを数量化II類と呼びます。説明変数に数値データとカテゴリカルデータが混在している場合は拡張型数量化II類と呼ばれます。


```python
df2 = pd.get_dummies(df.iloc[:, 2:], dummy_na=True)
X = df2
del X['Total']
del X['Sp. Atk']
del X['Sp. Def']
del X['Legendary']
X.head()
y = df['Legendary']
```


```python
#from sklearn.cross_validation import train_test_split # 訓練データとテストデータに分割
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.4) # 訓練データ・テストデータへのランダムな分割
```

## ロジスティック回帰

ロジスティック回帰については <a href="https://qiita.com/maskot1977/items/0f8a1ac961845735ce06">ロジスティック回帰を scipy.optimize.curve_fit で実装する</a> や <a href="https://qiita.com/maskot1977/items/3abe57187721258691cc">ロジスティック回帰をExcelで理解する</a> を参照のこと。


```python
from sklearn.linear_model import LogisticRegression # ロジスティック回帰
clf = LogisticRegression(solver='lbfgs', max_iter=10000) #モデルの生成
clf.fit(X_train, y_train) #学習
print("正解率(train): ", clf.score(X_train,y_train))
print("正解率(test): ", clf.score(X_test,y_test))
```

    正解率(train):  0.9479166666666666
    正解率(test):  0.93125



```python
from sklearn.metrics import confusion_matrix # 混合行列
# 予測結果と、正解（本当の答え）がどのくらい合っていたかを表す混合行列
pd.DataFrame(confusion_matrix(clf.predict(X_test), y_test), index=['predicted 0', 'predicted 1'], columns=['real 0', 'real 1'])
```

<img width="148" alt="スクリーンショット 2019-06-14 11.55.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/439e1ee6-58ef-3f37-cede-acd99ea0ba6b.png">


## 多層パーセプトロン

多層パーセプトロンについては <a href="https://qiita.com/maskot1977/items/6ae4f9d38b24017ad274">多層パーセプトロン (Multilayer perceptron, MLP)を scipy.optimize.curve_fit で実装する</a> や <a href="https://qiita.com/maskot1977/items/d0253e1eab1ff1315dff">多層パーセプトロン (Multilayer perceptron, MLP)をPythonで理解する</a> を参照のこと。


```python
from sklearn.neural_network import MLPClassifier
clf = MLPClassifier(max_iter=10000)
clf.fit(X_train, y_train) #学習
print("正解率(train): ", clf.score(X_train,y_train))
print("正解率(test): ", clf.score(X_test,y_test))
```

    正解率(train):  0.9625
    正解率(test):  0.934375



```python
from sklearn.metrics import confusion_matrix # 混合行列
# 予測結果と、正解（本当の答え）がどのくらい合っていたかを表す混合行列
pd.DataFrame(confusion_matrix(clf.predict(X_test), y_test), index=['predicted 0', 'predicted 1'], columns=['real 0', 'real 1'])
```

<img width="138" alt="スクリーンショット 2019-06-14 11.55.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/e94cd2e8-7436-3eed-0b80-c41ab09bfae1.png">



##  ランダムフォレスト

ランダムフォレストを使った分類もできます。ランダムフォレストについては <a href="https://www.slideshare.net/maskot3/ss-121401969">機械学習入門の入門</a> を参照のこと。


```python
from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier(n_estimators=100)
clf.fit(X_train, y_train) #学習
print("正解率(train): ", clf.score(X_train,y_train))
print("正解率(test): ", clf.score(X_test,y_test))
```

    正解率(train):  1.0
    正解率(test):  0.953125



```python
from sklearn.metrics import confusion_matrix # 混合行列
# 予測結果と、正解（本当の答え）がどのくらい合っていたかを表す混合行列
pd.DataFrame(confusion_matrix(clf.predict(X_test), y_test), index=['predicted 0', 'predicted 1'], columns=['real 0', 'real 1'])
```

<img width="137" alt="スクリーンショット 2019-06-14 11.56.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/9323159e-7683-0371-f803-8cb9fb8e2c5f.png">


feature importance を見てみましょう。 Sp. Atk を予測するために重要な変数と、伝説のポケモンかどうかを予測するために重要な変数は異なることがわかります。


```python
pd.DataFrame(clf.feature_importances_, index=list(X.columns)).sort_values(0, ascending=False).style.bar(subset=[0])
```

<img width="192" alt="スクリーンショット 2019-06-14 12.14.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/01a68583-0a7c-895e-687e-aab90f9d48c0.png">



## AUC スコアと ROC カーブ

分類問題の指標として AUC スコアと ROC カーブ があります。説明は <a href="https://www.randpy.tokyo/entry/roc_auc">【ROC曲線とAUC】機械学習の評価指標についての基礎講座</a> が詳しいです。


```python
from sklearn.metrics import roc_curve, precision_recall_curve, auc, classification_report, confusion_matrix
# AUCスコアを出す。
probas = clf.fit(X_train, y_train).predict_proba(X_test)
fpr, tpr, thresholds = roc_curve(y_test, probas[:, 1])
roc_auc = auc(fpr, tpr)
print ("ROC score : ",  roc_auc)
```

    ROC score :  0.9632107023411371



```python
# ROC curve を描く
plt.clf()
plt.plot(fpr, tpr, label='ROC curve (area = %0.2f)' % roc_auc)
plt.plot([0, 1], [0, 1], 'k--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.0])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver operating characteristic example')
plt.legend(loc="lower right")
plt.show()
```

![output_114_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/69b478cc-5837-1b12-58d3-aa9ce21aef7b.png)


## AUPR スコアと PR カーブ

インバランスデータ（正例と負例の数に大きな偏りがあるデータ）の場合はAUPR スコアと PR カーブで評価されることがあります。説明は <a href="https://aotamasaki.hatenablog.com/entry/2018/04/08/235339">インバランスデータにおいてPR曲線がROC曲線より優れているのをアニメーションで理解する。</a> が詳しいです。


```python
# AUPRスコアを出す
precision, recall, thresholds = precision_recall_curve(y_test, probas[:, 1])
area = auc(recall, precision)
print ("AUPR score: " , area)
```

    AUPR score:  0.760277018572971



```python
# PR curve を描く
plt.clf()
plt.plot(recall, precision, label='Precision-Recall curve')
plt.xlabel('Recall')
plt.ylabel('Precision')
plt.ylim([0.0, 1.05])
plt.xlim([0.0, 1.0])
plt.title('Precision-Recall example: AUPR=%0.2f' % area)
plt.legend(loc="lower left")
plt.show()
```

![output_117_0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211162/ec14cf3d-59ae-7e18-32a6-ccf55deff612.png)


最後まで読んでくれてありがとうございます。

# これで君もポケモンマスターだ！