重回帰分析とポケモン種族値

```python
# Program Name: pokemon_stat_sum_regression.py  
# Creation Date: 20250603  
# Overview: Predict total base stats using Attack, Sp. Atk, and Speed for 80 real Pokémon  
# Usage: Run in Python environment after installing required libraries  

# -------------------- Install Required Libraries --------------------
!pip install pandas numpy scikit-learn matplotlib

# -------------------- Import Libraries --------------------
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression

# -------------------- Sample Pokémon Data (80 Pokémon) --------------------
# 実在ポケモンのデータ80体分（攻撃・特攻・素早さ・合計種族値） / 80 Pokémon with base stats
data = [
    ['Pikachu', 55, 50, 90, 320], ['Charizard', 84, 109, 100, 534], ['Blastoise', 83, 85, 78, 530],
    ['Venusaur', 82, 100, 80, 525], ['Gengar', 65, 130, 110, 500], ['Alakazam', 50, 135, 120, 500],
    ['Machamp', 130, 65, 55, 505], ['Gyarados', 125, 60, 81, 540], ['Snorlax', 110, 65, 30, 540],
    ['Dragonite', 134, 100, 80, 600], ['Togekiss', 50, 120, 80, 545], ['Salamence', 135, 110, 100, 600],
    ['Metagross', 135, 95, 70, 600], ['Lucario', 110, 115, 90, 525], ['Infernape', 104, 104, 108, 534],
    ['Torterra', 109, 75, 56, 525], ['Empoleon', 86, 111, 60, 530], ['Garchomp', 130, 80, 102, 600],
    ['Roserade', 70, 125, 90, 515], ['Staraptor', 120, 50, 100, 475], ['Luxray', 120, 95, 70, 523],
    ['Gardevoir', 65, 125, 80, 518], ['Flygon', 100, 80, 100, 520], ['Haxorus', 147, 60, 97, 540],
    ['Sylveon', 65, 110, 60, 525], ['Noivern', 70, 97, 123, 535], ['Aegislash', 50, 140, 60, 500],
    ['Dragapult', 120, 100, 142, 600], ['Corviknight', 87, 53, 67, 495], ['Tinkaton', 75, 70, 94, 506],
    ['Zoroark', 105, 120, 105, 510], ['Hydreigon', 105, 125, 98, 600], ['Mimikyu', 90, 50, 96, 476],
    ['Grimmsnarl', 120, 95, 60, 510], ['Excadrill', 135, 50, 88, 508], ['Darmanitan', 140, 30, 95, 480],
    ['Cinderace', 116, 65, 119, 530], ['Decidueye', 107, 100, 70, 530], ['Samurott', 108, 100, 70, 528],
    ['Goodra', 100, 110, 80, 600], ['Hawlucha', 92, 74, 118, 500], ['Talonflame', 81, 74, 126, 499],
    ['Amoonguss', 85, 85, 30, 464], ['Chandelure', 60, 145, 80, 520], ['Krookodile', 117, 65, 92, 519],
    ['Galvantula', 77, 97, 108, 472], ['Durant', 109, 48, 109, 484], ['Dragalge', 75, 97, 44, 494],
    ['Aegislash-Blade', 140, 140, 60, 520], ['Kommo-o', 110, 100, 85, 600], ['Obstagoon', 90, 60, 95, 520],
    ['Espeon', 65, 130, 110, 525], ['Scizor', 130, 55, 65, 500], ['Togetic', 40, 80, 40, 405],
    ['Sharpedo', 120, 95, 95, 460], ['Milotic', 60, 100, 81, 540], ['Magmortar', 95, 125, 83, 540],
    ['Electivire', 123, 95, 95, 540], ['Drapion', 90, 60, 95, 500], ['Glaceon', 60, 130, 65, 525],
    ['Leafeon', 110, 60, 95, 525], ['Scolipede', 100, 55, 112, 485], ['Reuniclus', 65, 125, 30, 490],
    ['Cinccino', 95, 65, 115, 470], ['Braviary', 123, 57, 80, 510], ['Whimsicott', 67, 77, 116, 480],
    ['Gigalith', 135, 60, 25, 515], ['Conkeldurr', 140, 55, 45, 505], ['Thundurus', 115, 125, 111, 580],
    ['Landorus', 125, 115, 101, 600], ['Tornadus', 100, 115, 111, 580], ['Accelgor', 70, 100, 145, 495],
    ['Bisharp', 125, 60, 70, 505], ['Houndoom', 90, 110, 95, 500], ['Manectric', 75, 105, 105, 475],
    ['Banette', 115, 83, 65, 455], ['Froslass', 80, 80, 110, 480], ['Crobat', 90, 70, 130, 535],
    ['Shiftry', 100, 90, 80, 480], ['Tropius', 68, 72, 51, 460], ['Claydol', 70, 70, 75, 500]
]

# -------------------- DataFrame Conversion --------------------
df = pd.DataFrame(data, columns=['Name', 'Attack', 'SpAttack', 'Speed', 'Total'])

# -------------------- Linear Regression --------------------
X = df[['Attack', 'SpAttack', 'Speed']]  # 説明変数 / Features
y = df['Total']                          # 目的変数 / Target

model = LinearRegression()
model.fit(X, y)

# 回帰係数・切片表示 / Display regression coefficients
coef = model.coef_
intercept = model.intercept_
print(f"Estimated Total Stat Function:")
print(f"Total = {intercept:.2f} + ({coef[0]:.2f})*Attack + ({coef[1]:.2f})*SpAttack + ({coef[2]:.2f})*Speed")

# -------------------- 推定結果をデータフレームに追加 / Add Predicted Total --------------------
df['PredictedTotal'] = model.predict(X).round(1)

# -------------------- 結果表示 / Show table --------------------
print(df[['Name', 'Attack', 'SpAttack', 'Speed', 'Total', 'PredictedTotal']])

# -------------------- Visualization --------------------
plt.figure(figsize=(18, 6))
plt.plot(df['Name'], df['Total'], marker='o', label='True Total')
plt.plot(df['Name'], df['PredictedTotal'], marker='x', label='Predicted Total')
plt.xticks(rotation=90)
plt.xlabel("Pokémon")
plt.ylabel("Total Base Stats")
plt.title("True vs Predicted Total Base Stats (80 Pokémon)")
plt.legend()
plt.tight_layout()
plt.grid(True)
plt.show()

```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4046871/88ec509a-3e9c-40bb-a730-91eab35c020d.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4046871/3f829082-30ee-4a42-b35d-381770c71739.png)