#はじめに
機械学習をしてみたいと思って、選ばれたのが『ポケモン』でした。
ポケモンは種族値がポケモンごとに決まっているので、データの宝石箱だと考えました。
しかし、今回はGoogleで『ポケモン 機械学習』で検索してトップに出てきた人のものを参考にした完全下位互換記事なので、真似したい方は是非元記事をご参照ください。
ポケモンで学ぶ機械学習
#環境
OS:Win10 home
IDE:VScode
言語:python 3.7.3 64bit
#やったこと
7世代までのポケモンのデータベースを元に、『ひこう』、『エスパー』のポケモンを抽出して、ロジスティック回帰で二値分類させてみました。
ちなみに、ポケモンにおける各タイプの数は以下(7世代まで)
タイプ | 匹数 |
---|---|
ノーマル | 116匹 |
かくとう | 63匹 |
どく | 69匹 |
じめん | 75匹 |
ひこう | 113匹 |
むし | 89匹 |
いわ | 67匹 |
ゴースト | 55匹 |
はがね | 58匹 |
ほのお | 72匹 |
みず | 141匹 |
でんき | 60匹 |
くさ | 103匹 |
こおり | 43匹 |
エスパー | 100匹 |
ドラゴン | 59匹 |
あく | 59匹 |
フェアリー | 54匹 |
みずが最多で、こおりが最小でしたね。フリーズドライで倍返しですね。
Codeは以下です。
import pandas as pd
import codecs
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
# read data by pandas
with codecs.open("data/pokemon_status.csv", "r", "Shift-JIS", "ignore") as file:
df = pd.read_table(file, delimiter=",")
# print(df.head(15))
p_type = ["ノーマル","かくとう","どく","じめん","ひこう","むし","いわ","ゴースト","はがね","ほのお","みず","でんき","くさ","こおり","エスパー","ドラゴン","あく","フェアリー"]
print(len(p_type))
# make functions
def count_type(p_type):
list1 = df[df['タイプ1'] == p_type]
list2 = df[df['タイプ2'] == p_type]
lists = pd.concat([list1, list2])
print(p_type + "のポケモン: %d匹" % len(lists))
def type_to_num(p_type):
if p_type == "ひこう":
return 1
else:
return 0
# count number of type in pokemons
for i in p_type:
count_type(i)
# make sky_df
sky1 = df[df['タイプ1'] == "ひこう"]
sky2 = df[df['タイプ2'] == "ひこう"]
sky = pd.concat([sky1, sky2])
# make psycho_df
psycho1 = df[df['タイプ1'] == "エスパー"]
psycho2 = df[df['タイプ2'] == "エスパー"]
psycho = pd.concat([psycho1, psycho2])
df_s_p = pd.concat([sky, psycho], ignore_index=True)
type1 = df_s_p['タイプ1'].apply(type_to_num)
type2 = df_s_p['タイプ2'].apply(type_to_num)
df_s_p['type_num'] = type1 + type2
print(df_s_p)
X = df_s_p.iloc[:,7:13].values
y = df_s_p['type_num'].values
X_train,X_test,y_train,y_test = train_test_split(X, y, test_size = 0.3, random_state = 0)
lr = LogisticRegression(C = 1.0)
lr.fit(X_train, y_train)
# show scores
print("train_score: %.3f" % lr.score(X_train, y_train))
print("test_score: %.3f" % lr.score(X_test, y_test))
i = 0
error1 = 0
success1 = 0
error2 = 0
success2 = 0
print("[ひこうタイプと判断したポケモン一覧]")
print("----------------------------------------")
print("")
while i < len(df_s_p):
y_pred = lr.predict(X[i].reshape(1, -1))
if y_pred == 1:
print(df_s_p.loc[i, ["ポケモン名"]])
if df_s_p.loc[i, ["type_num"]].values == 1:
success1 += 1
print("ひこうタイプですよね")
print("")
else:
error1 += 1
print("ひこうタイプやと思ってしまいました")
print("")
else:
print(df_s_p.loc[i, ["ポケモン名"]])
if df_s_p.loc[i, ["type_num"]].values == 0:
error2 += 1
print("エスパータイプですよね")
print("")
else:
success2 += 1
print("エスパータイプやと思ってしましました")
print("")
i += 1
print("----------------------------------------")
print("正しくひこうタイプと判断したポケモンの数: %d匹" % success1)
print("正しくエスパータイプと判断したポケモンの数: %d匹" % success2)
print("誤ってひこうタイプと判断したポケモンの数: %d匹" % error1)
print("誤ってエスパータイプと判断したポケモンの数: %d匹" % error2)
print("")
#結果
結果は正答率75%でした。低いですね。機械学習では使えない数値でした。
私はもっと良い数字がでると思ったんですけどね。なぜなら『ひこう』なら物理アタッカー、『エスパー』なら特殊アタッカーと大まかに分けられるかなと思ったからです。現実はそんなに単純ではありませんね。
とはいえ、実際に誤検知されたポケモンを見ると私でも誤検知してしまうなーという理由が得られました。
例えば、ひこうなのにエスパーと間違えられた子として『サンダー』、『フリーザー』がいたのですが、とくこうが高いのでそりゃそうよな。俺でも初見なら間違えるわ、となりました。
逆に、エスパーなのにひこうと間違えられた子として『ケーシィ』、『ラルトス』がいたのですが、これは低種族値なので仕方ないかなと思いました。低種族値帯では数値に差がつきにくいので。
進化系の『フーディン』や『サーナイト』、『エルレイド』はばっこしエスパーに割り振られていたので安心です。
ん??
![erureido.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208060/08320895-7b06-30f7-e6c0-c5a2080413b6.jpeg)
エルレイドはんっ!
あんたはひこうタイプに間違われても良かったんちゃいまっか!!!
#おわりに
やはり種族値だけでポケモンを判断するのは間違っている 完