ポケモン種族値を用いた**ナイーブベイズ・k-NN・SVMの分類器比較**


```python
# 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()
```

---

### 🔍解説（コード外）：

* **Naive Bayes**：特徴量の独立性を仮定。少量データでも学習可能。
* **k-NN**：ラベル多数・近傍中心の構造に強い。過学習しにくいが計算重い。
* **SVM**：高次元空間での線形分離に強い。小データでも高精度になる傾向。

---