【kaggle】ポケモンデータでlightGBMしてみる

機械学習

カグルにこんなんありました『Pokemon with stats』、ポケモンのデータです。800種類のポケモンの
基本的な統計(HP、攻撃、防御、特殊攻撃、特殊防御、速度等)情報がまとまってるとのこと。伝説ポケモンかそうでないか、というデータも入っていますので、どの特徴量が伝説ポケモンたらしめているのか、を見ていこうと思います。こちらも前回『【kaggle】離婚予測データでlightGBMしてみる』使ったlightGBMでやっていこうと思います。

データの確認と準備

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
plt.style.use("ggplot")
from sklearn import metrics
from sklearn.model_selection import train_test_split

import lightgbm as lgb
from sklearn.preprocessing import LabelEncoder

いつものやつと、カテゴリデータがあるので、ラベルエンコーダーもインポートしておきます。

df=pd.read_csv("/content/drive/MyDrive/Colab Notebooks/Pokemon.csv")
df.head(10)                 

データフレームとして読み込んで表示します。

#NameType 1Type 2TotalHPAttackDefenseSp. AtkSp. DefSpeedGenerationLegendary
01BulbasaurGrassPoison3184549496565451FALSE
12IvysaurGrassPoison4056062638080601FALSE
23VenusaurGrassPoison525808283100100801FALSE
33VenusaurMega VenusaurGrassPoison62580100123122120801FALSE
44CharmanderFireNaN3093952436050651FALSE
55CharmeleonFireNaN4055864588065801FALSE
66CharizardFireFlying534788478109851001FALSE
76CharizardMega Charizard XFireDragon63478130111130851001FALSE
86CharizardMega Charizard YFireFlying63478104781591151001FALSE
97SquirtleWaterNaN3144448655064431FALSE

こういう感じです。ほとんど知らないんですが、Type1が大カテゴリ、Type2が中カテゴリみたいなことなんでしょう。Generation、これもおそらく世に出た順番みたいなものでしょう。
で、Legendaryに伝説か、そうでないか、が入ってます。

df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 800 entries, 0 to 799
Data columns (total 13 columns):
 #   Column      Non-Null Count  Dtype 
---  ------      --------------  ----- 
 0   #           800 non-null    int64 
 1   Name        800 non-null    object
 2   Type 1      800 non-null    object
 3   Type 2      414 non-null    object
 4   Total       800 non-null    int64 
 5   HP          800 non-null    int64 
 6   Attack      800 non-null    int64 
 7   Defense     800 non-null    int64 
 8   Sp. Atk     800 non-null    int64 
 9   Sp. Def     800 non-null    int64 
 10  Speed       800 non-null    int64 
 11  Generation  800 non-null    int64 
 12  Legendary   800 non-null    bool  
dtypes: bool(1), int64(9), object(3)
memory usage: 75.9+ KB

こんな感じ。これも見ておきます。

df.nunique()
#             721
Name          800
Type 1         18
Type 2         18
Total         200
HP             94
Attack        111
Defense       103
Sp. Atk       105
Sp. Def        92
Speed         108
Generation      6
Legendary       2
dtype: int64

なるほど、Type1は18種もありますね。Type2はないポケモンもいるようなので、これ以外でやっていきます。

df_=df.drop(["#","Name","Type 2","Legendary"],axis=1)
df_.head(10)
Type 1TotalHPAttackDefenseSp. AtkSp. DefSpeedGeneration
0Grass3184549496565451
1Grass4056062638080601
2Grass525808283100100801
3Grass62580100123122120801
4Fire3093952436050651
5Fire4055864588065801
6Fire534788478109851001
7Fire63478130111130851001
8Fire63478104781591151001
9Water3144448655064431

Type1を数値化していきます。決定木ベースのlightGBMを使うので、そのままラベルエンコーディングします。

x=df_

type1_le=LabelEncoder()
x["Type 1"]=type1_le.fit_transform(x["Type 1"])
x.head(10)
Type 1TotalHPAttackDefenseSp. AtkSp. DefSpeedGeneration
093184549496565451
194056062638080601
29525808283100100801
3962580100123122120801
463093952436050651
564055864588065801
66534788478109851001
7663478130111130851001
8663478104781591151001
9173144448655064431

これで特徴量は用意できました。次にターゲットの方ですね。

t=df.iloc[:,-1]
t=t.astype(np.int)

簡単です。true/falseは型を変えるだけで1,0になってくれます。あとは、いつもの通り、スプリットします。

x_train,x_test,t_train,t_test=train_test_split(x,t,test_size=0.3,random_state=0)
print(x_train.shape,x_test.shape,t_train.shape,t_test.shape)
(560, 9) (240, 9) (560,) (240,)

これにて、データの準備が整いました。

lightGBMで学習

lgb_train=lgb.Dataset(x_train,t_train)
lgb_eval=lgb.Dataset(x_test,t_test)

params = {"metric":"auc",
          "objective":"binary", 
          "max_depth":7}

lgbm = lgb.train(params,
                lgb_train,
                valid_sets=lgb_eval,
                num_boost_round=1000,
                early_stopping_rounds=50,
                verbose_eval=50)
Training until validation scores don't improve for 50 rounds.
[50]	valid_0's auc: 0.986375
Early stopping, best iteration is:
[45]	valid_0's auc: 0.988179

いつもの通り、一瞬で終わります。正解率は、

print(metrics.accuracy_score(t_train.values,np.round(lgbm.predict(x_train))))
print(metrics.accuracy_score(t_test.values,np.round(lgbm.predict(x_test))))
0.9946428571428572
0.9625

やはり、素晴らしい数値をたたき出します。

伝説ポケモンたらしめる特徴量は何か?

imp=pd.DataFrame(np.round(lgbm.feature_importance(importance_type="gain"),2), index=x.columns, columns=["importance"])
imp=imp.sort_values("importance",ascending=False)
imp
importance
Total1051.98
Generation80.33
Attack53.57
Sp. Atk42.22
HP38.13
Speed35.83
Type 125.57
Sp. Def21.89
Defense17.92

HPからSpeedまでの合計がTotalなんですが、これが大きいとだいたい伝説ポケモン、というシンプルで一貫性のある結果が得られました。どうもありがとうございました。