# Program Name: pokemon_type_classification_comparison.py
# Creation Date: 20250603
# Overview: Predict Pokémon type from base stats using Naive Bayes, k-NN, and SVM, and compare their performance
# Usage: Run in Python environment with scikit-learn, matplotlib, seaborn installed
# -------------------- Install Required Libraries --------------------
!pip install pandas numpy scikit-learn matplotlib seaborn
# -------------------- Import Libraries --------------------
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder, StandardScaler
from sklearn.naive_bayes import GaussianNB
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC
from sklearn.metrics import classification_report, confusion_matrix, ConfusionMatrixDisplay
# -------------------- Constants / 定数定義 --------------------
RANDOM_STATE = 42 # 乱数シード / Random seed
TEST_SIZE = 0.3 # テストデータの割合 / Test data ratio
K_NEIGHBORS = 3 # k-NNにおける近傍数 / Number of neighbors for k-NN
# -------------------- Sample Data / サンプルデータ定義 --------------------
# ポケモン名・種族値・タイプを含むデータフレーム / Pokémon data including stats and types
data = {
'Name': ['Pikachu', 'Charizard', 'Blastoise', 'Venusaur', 'Gengar',
'Machamp', 'Alakazam', 'Snorlax', 'Gyarados', 'Dragonite'],
'HP': [35, 78, 79, 80, 60, 90, 55, 160, 95, 91],
'Attack': [55, 84, 83, 82, 65, 130, 50, 110, 125, 134],
'Defense': [40, 78, 100, 83, 60, 80, 45, 65, 79, 95],
'Sp. Atk': [50, 109, 85, 100, 130, 65, 135, 65, 60, 100],
'Sp. Def': [50, 85, 105, 100, 75, 85, 95, 110, 100, 100],
'Speed': [90, 100, 78, 80, 110, 55, 120, 30, 81, 80],
'Type': ['Electric', 'Fire', 'Water', 'Grass', 'Ghost',
'Fighting', 'Psychic', 'Normal', 'Water', 'Dragon']
}
df = pd.DataFrame(data)
# -------------------- Encode Labels / タイプの数値変換 --------------------
# 文字列のタイプ名を数値ラベルに変換 / Convert type string to numeric labels
le = LabelEncoder()
df['Type_Label'] = le.fit_transform(df['Type']) # 例: Electric → 0, Fire → 1, ...
# -------------------- Feature and Target / 特徴量と目的変数 --------------------
X = df[['HP', 'Attack', 'Defense', 'Sp. Atk', 'Sp. Def', 'Speed']]
y = df['Type_Label']
# -------------------- Standardize Features / 特徴量の標準化 --------------------
# 全分類器で共通化のため標準化 / Standardization for fair comparison
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# -------------------- Train-Test Split / 学習用・評価用データの分割 --------------------
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=TEST_SIZE, random_state=RANDOM_STATE)
# -------------------- Model Training / モデルの学習 --------------------
# Gaussian Naive Bayes / ガウス分布仮定のナイーブベイズ分類器
nb_model = GaussianNB()
nb_model.fit(X_train, y_train)
y_pred_nb = nb_model.predict(X_test)
# k-Nearest Neighbors / k最近傍法
knn_model = KNeighborsClassifier(n_neighbors=K_NEIGHBORS)
knn_model.fit(X_train, y_train)
y_pred_knn = knn_model.predict(X_test)
# Support Vector Machine / サポートベクターマシン(線形カーネル)
svm_model = SVC(kernel='linear', probability=True)
svm_model.fit(X_train, y_train)
y_pred_svm = svm_model.predict(X_test)
# -------------------- Evaluation Function / 評価表示関数 --------------------
def evaluate_model(name, y_true, y_pred):
print(f"\n{name} - Classification Report")
print(classification_report(y_true, y_pred, target_names=le.classes_))
cm = confusion_matrix(y_true, y_pred)
disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=le.classes_)
disp.plot(cmap='Blues')
plt.title(f'{name} - Confusion Matrix')
plt.grid(False)
plt.show()
# -------------------- Display Evaluation / 各モデルの評価出力 --------------------
evaluate_model("Naive Bayes", y_test, y_pred_nb)
evaluate_model("k-NN", y_test, y_pred_knn)
evaluate_model("SVM", y_test, y_pred_svm)
# -------------------- Data Visualization / 種族値とタイプの関係 --------------------
# 攻撃と特攻を散布図で視覚化 / Visualize relationship between Attack and Sp. Atk
plt.figure(figsize=(10, 6))
sns.scatterplot(x='Attack', y='Sp. Atk', hue='Type', data=df, s=100)
plt.title('Pokemon by Attack and Special Attack')
plt.xlabel('Attack')
plt.ylabel('Special Attack')
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left')
plt.grid(True)
plt.tight_layout()
plt.show()