查看原文
其他

为了找到最强神奇宝贝战队,我建了个数学模型

王海华 模型视角 2023-09-06

在《神奇宝贝》的世界中,每个训练师都梦想拥有最强大的神奇宝贝队伍,与其他训练家竞争并成为冠军。但在数百种不同的神奇宝贝中,如何选择哪六只组成您的梦之队呢?直觉和经验当然很重要,但我想尝试一种不同的方法:使用数学模型。是的,你没听错,为了在这场宝可梦战争中取得胜利,我决定引入一些数学魔法!

这个数据集来自kaggle,包含了所有七代的802只神奇宝贝的信息。这个数据集中的信息包括基础属性、对其他种类的性能、身高、体重、分类、孵蛋步数、经验值、能力等。这些信息是从 http://serebii.net/ 爬取的。

下面是数据列名及含义:

name: 神奇宝贝的英文名称

japanese_name: 神奇宝贝的原始日文名称

pokedex_number: 神奇宝贝在全国图鉴中的编号

percentage_male: 该物种为雄性的百分比。如果神奇宝贝没有性别,则此处为空。

type1: 神奇宝贝的主要属性

type2: 神奇宝贝的次要属性

classification: 太阳与月亮图鉴中描述的神奇宝贝的分类

height_m: 神奇宝贝的身高(以米为单位)

weight_kg: 神奇宝贝的体重(以千克为单位)

capture_rate: 神奇宝贝的捕获率

base_egg_steps: 孵化神奇宝贝的蛋所需的步数

abilities: 神奇宝贝所能拥有的能力的字符串列表

experience_growth: 神奇宝贝的经验增长

base_happiness: 神奇宝贝的基础幸福度

against_?: 18个特性,表示对某种特定类型的攻击受到的伤害量

hp: 神奇宝贝的基础HP值

attack: 神奇宝贝的基础攻击值

defense: 神奇宝贝的基础防御值

sp_attack: 神奇宝贝的基础特殊攻击值

sp_defense: 神奇宝贝的基础特殊防御值

speed: 神奇宝贝的基础速度值

generation: 首次介绍神奇宝贝的代数

is_legendary: 表示神奇宝贝是否是传说的。

数据是从 http://serebii.net/ 爬取的。

通过这个数据集,我们想回答以下问题

  • 是否可以构建一个分类器来识别传说的神奇宝贝?
  • 神奇宝贝的身高和体重如何与其各种基础属性相关?
  • 哪些因素影响经验增长和孵蛋步数?这些数量是否相关?
  • 哪种类型总体上最强?哪种是最弱的?
  • 哪种类型最有可能是传说的神奇宝贝?
  • 我们能否组建一个神奇宝贝梦之队吗?一个由6只神奇宝贝组成的队伍,能够造成最大的伤害,同时对其他任何6只神奇宝贝的队伍都相对不受伤害。

数据集的样子如下:

import pandas as pd

# Load the dataset
pokemon_df = pd.read_csv('data/pokemon.csv')

# Display the first few rows of the dataset to understand its structure
pokemon_df.head()
                     abilities  against_bug  against_dark  against_dragon  \
0  ['Overgrow''Chlorophyll']          1.0           1.0             1.0   
1  ['Overgrow''Chlorophyll']          1.0           1.0             1.0   
2  ['Overgrow''Chlorophyll']          1.0           1.0             1.0   
3     ['Blaze''Solar Power']          0.5           1.0             1.0   
4     ['Blaze''Solar Power']          0.5           1.0             1.0   

   against_electric  against_fairy  against_fight  against_fire  \
0               0.5            0.5            0.5           2.0   
1               0.5            0.5            0.5           2.0   
2               0.5            0.5            0.5           2.0   
3               1.0            0.5            1.0           0.5   
4               1.0            0.5            1.0           0.5   

   against_flying  against_ghost  ...  percentage_male  pokedex_number  \
0             2.0            1.0  ...             88.1               1   
1             2.0            1.0  ...             88.1               2   
2             2.0            1.0  ...             88.1               3   
3             1.0            1.0  ...             88.1               4   
4             1.0            1.0  ...             88.1               5   

   sp_attack  sp_defense  speed  type1   type2  weight_kg  generation  \
0         65          65     45  grass  poison        6.9           1   
1         80          80     60  grass  poison       13.0           1   
2        122         120     80  grass  poison      100.0           1   
3         60          50     65   fire     NaN        8.5           1   
4         80          65     80   fire     NaN       19.0           1   

   is_legendary  
0             0  
1             0  
2             0  
3             0  
4             0  

[5 rows x 41 columns]

让我们开始回答这些问题。首先,我们将尝试构建一个分类器来识别传说的神奇宝贝。

问题1: 是否可以构建一个分类器来识别传说(legendary)的神奇宝贝?

为了回答这个问题,我们首先需要查看传说的神奇宝贝(is_legendary)与其他属性的关系。这可以通过简单的数据探索和可视化来完成。但在构建分类器之前,我们先了解数据的分布。

让我们首先查看传说的神奇宝贝的分布情况。

# Distribution of Legendary vs Non-Legendary Pokemon
legendary_distribution = pokemon_df['is_legendary'].value_counts(normalize=True) * 100

legendary_distribution

结果

RESULT
0    91.260924
1     8.739076
Name: is_legendary, dtype: float64

传说的神奇宝贝占数据集的约8.74%,非传说的神奇宝贝占约91.26%。这意味着我们的数据集是不平衡的,这可能会影响分类器的性能。在实际建模时,我们可能需要采取策略来处理这种不平衡。

在构建分类器之前,让我们进一步探索数据,查看一些属性与是否为传说的神奇宝贝之间的关系。这可以帮助我们了解哪些属性可能对分类器有帮助。

例如,我们可以查看传说的神奇宝贝的基础属性(如HP、攻击、防御等)的分布,与非传说的神奇宝贝进行比较。让我们可视化这些分布。

import matplotlib.pyplot as plt
import seaborn as sns

# Define the stats to compare
stats = ['hp''attack''defense''sp_attack''sp_defense''speed']

# Plot distributions for Legendary vs Non-Legendary Pokemon
plt.figure(figsize=(1510))

for i, stat in enumerate(stats, 1):
    plt.subplot(23, i)
    sns.kdeplot(pokemon_df[pokemon_df['is_legendary'] == 0][stat], label='Non-Legendary', shade=True)
    sns.kdeplot(pokemon_df[pokemon_df['is_legendary'] == 1][stat], label='Legendary', shade=True)
    plt.title(stat.capitalize())
    plt.legend()

plt.tight_layout()
plt.show()

从上述分布图中,我们可以观察到:

  • 传说的神奇宝贝在基础属性如HP、攻击、特殊攻击、特殊防御和速度上通常都有更高的值。
  • 非传说的神奇宝贝在这些属性上的分布更为广泛,而传说的神奇宝贝更倾向于集中在高值区域。

这意味着这些属性可能对于识别一个神奇宝贝是否为传说的神奇宝贝非常有用。

接下来,我们可以构建一个简单的分类器来尝试预测神奇宝贝是否为传说的。在此,我们将使用随机森林分类器作为一个示例,实际上可能需要进行更多的特征工程和模型调优来获得最佳的预测性能。

from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report, accuracy_score

# Features and target
X = pokemon_df[stats]
y = pokemon_df['is_legendary']

# Splitting the data into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42, stratify=y)

# Initialize a Random Forest Classifier
clf = RandomForestClassifier(random_state=42)

# Train the classifier
clf.fit(X_train, y_train)

# Make predictions
y_pred = clf.predict(X_test)

# Evaluate the classifier
accuracy = accuracy_score(y_test, y_pred)
classification_rep = classification_report(y_test, y_pred)

accuracy, classification_rep

结果:

(0.941908713692946,
 '              precision    recall  f1-score   support\n\n           0       0.94      1.00      0.97       220\n           1       0.89      0.38      0.53        21\n\n    accuracy                           0.94       241\n   macro avg       0.92      0.69      0.75       241\nweighted avg       0.94      0.94      0.93       241\n')

使用随机森林分类器,我们获得了约94.19%的准确率。但是,从分类报告中我们可以看到:

  • 对于非传说的神奇宝贝,我们获得了非常高的精确度和召回率。
  • 对于传说的神奇宝贝,虽然精确度为89%,但召回率只有38%。这意味着我们的模型错过了很多真正的传说神奇宝贝。
  • 这是由于数据的不平衡性所导致的。为了改进模型,我们可能需要考虑使用过采样、欠采样或使用合成数据增强技术。此外,进行更多的特征工程和参数调优也可能有助于提高模型的性能。

问题2: 神奇宝贝的身高和体重如何与其各种基础属性相关?

为了回答这个问题,我们可以计算身高 (height_m) 和体重 (weight_kg) 与其他基础属性之间的相关性。

# Calculate the correlation of 'height_m' and 'weight_kg' with other base stats
correlation_with_height = pokemon_df[stats + ['height_m']].corr()['height_m'].drop('height_m')
correlation_with_weight = pokemon_df[stats + ['weight_kg']].corr()['weight_kg'].drop('weight_kg')

correlation_with_height, correlation_with_weight

根据计算得到的相关性数据:

(hp            0.478369
 attack        0.423160
 defense       0.361938
 sp_attack     0.353007
 sp_defense    0.328327
 speed         0.202202
 Name: height_m, dtype: float64,
 hp            0.427743
 attack        0.382183
 defense       0.424067
 sp_attack     0.245218
 sp_defense    0.306523
 speed         0.051384
 Name: weight_kg, dtype: float64)

与身高 (height_m) 的相关性:

  • HP、攻击、防御、特殊攻击和特殊防御与身高都有中等的正相关性。
  • 速度与身高的相关性相对较低。

与体重 (weight_kg) 的相关性:

  • HP、攻击、防御和特殊防御与体重有中等的正相关性。
  • 速度与体重的相关性非常低。

这意味着,更高或更重的神奇宝贝通常在HP、攻击和防御等属性上有更高的值,但速度可能不会受到太大影响。

接下来,我们将解决第三个问题。

问题3: 哪些因素影响经验增长和孵蛋步数?这些数量是否相关?

首先,让我们查看经验增长 (experience_growth) 和孵蛋步数 (base_egg_steps) 之间的相关性,然后再看这两个属性与其他属性之间的相关性。

# Calculate the correlation between 'experience_growth' and 'base_egg_steps'
correlation_between_exp_and_egg = pokemon_df['experience_growth'].corr(pokemon_df['base_egg_steps'])

# Calculate the correlation of 'experience_growth' and 'base_egg_steps' with other base stats
correlation_with_exp = pokemon_df[stats + ['experience_growth']].corr()['experience_growth'].drop('experience_growth')
correlation_with_egg_steps = pokemon_df[stats + ['base_egg_steps']].corr()['base_egg_steps'].drop('base_egg_steps')
correlation_between_exp_and_egg, correlation_with_exp, correlation_with_egg_steps

以下是我们的发现:

  • 经验增长 (experience_growth) 与孵蛋步数 (base_egg_steps) 之间有一个中等的正相关性(约为0.37)。

  • 与经验增长 (experience_growth) 的相关性:攻击、HP和特殊攻击与经验增长有正相关性。

  • 与孵蛋步数 (base_egg_steps) 的相关性:所有基础属性(如HP、攻击、特殊攻击等)与孵蛋步数都有正相关性,其中特殊攻击与孵蛋步数的相关性最高。

这意味着,需要更多经验增长或孵蛋步数的神奇宝贝通常在基础属性上有更高的值。

接下来,我们将解决第四个问题。

问题4: 哪种类型总体上最强?哪种是最弱?

为了回答这个问题,我们需要定义"最强"和"最弱"的标准。一个简单的方法是根据神奇宝贝的总体基础属性来评估。我们可以计算每种类型的神奇宝贝的平均总属性值,然后进行比较。

让我们进行这个分析。

# Calculate total base stats for each Pokemon
pokemon_df['total_stats'] = pokemon_df[stats].sum(axis=1)

# Calculate the average total base stats for each type (both type1 and type2)
average_stats_type1 = pokemon_df.groupby('type1')['total_stats'].mean()
average_stats_type2 = pokemon_df.groupby('type2')['total_stats'].mean()

# Combine the results and calculate the overall average
overall_average_stats = (average_stats_type1 + average_stats_type2).dropna() / 2

# Sort the types by overall average stats
sorted_overall_average_stats = overall_average_stats.sort_values(ascending=False)

sorted_overall_average_stats

结果如下:

RESULT
type1
dragon      510.124183
steel       493.768939
psychic     464.838972
fighting    459.090714
fire        458.009615
ice         450.737681
ghost       449.494709
dark        447.355501
flying      447.350877
electric    446.799145
rock        446.669048
ground      428.061581
fairy       426.066092
water       416.188854
grass       414.613462
normal      406.397619
poison      397.957721
bug         380.515278
Name: total_stats, dtype: float64

基于平均总属性值,我们得到了以下的神奇宝贝类型排名:

  • 最强的类型:龙 (Dragon) 类型,其平均总属性值为510.12。
  • 最弱的类型:虫 (Bug) 类型,其平均总属性值为380.52。 从这个分析中,我们可以看到龙类型的神奇宝贝在所有的类型中平均性能最好,而虫类型的神奇宝贝的平均性能相对较差。

但要注意,单纯依赖平均总属性值来判断一个类型的强度可能过于简化。实际游戏中,神奇宝贝的实际强度还受到其属性组合、技能、训练者策略等多种因素的影响。

接下来,我们将解决第五个问题。

问题5: 哪种类型最有可能是传说的神奇宝贝?

为了回答这个问题,我们可以计算每种类型的神奇宝贝中有多少百分比是传说的神奇宝贝。

# Calculate the percentage of Legendary Pokemon for each type (both type1 and type2)
legendary_percentage_type1 = pokemon_df.groupby('type1')['is_legendary'].mean() * 100
legendary_percentage_type2 = pokemon_df.groupby('type2')['is_legendary'].mean() * 100

# Combine the results and calculate the overall average percentage
overall_legendary_percentage = (legendary_percentage_type1 + legendary_percentage_type2).dropna() / 2

# Sort the types by overall legendary percentage
sorted_overall_legendary_percentage = overall_legendary_percentage.sort_values(ascending=False)

sorted_overall_legendary_percentage

结果如下:

type1
dragon      24.727669
psychic     22.934288
flying      21.929825
steel       21.590909
fairy       13.122605
fire        12.500000
fighting    12.000000
electric    11.965812
ghost        8.994709
ice          7.681159
grass        7.564103
water        5.572755
dark         5.172414
ground       4.595588
rock         4.444444
bug          2.083333
poison       1.470588
normal       1.428571
Name: is_legendary, dtype: float64

基于每种类型中传说神奇宝贝的百分比,我们得到以下的排名:

  • 最有可能是传说的类型:龙 (Dragon) 类型,约24.73%的龙类型神奇宝贝是传说的。
  • 最不可能是传说的类型:普通 (Normal) 类型,只有约1.43%的普通类型神奇宝贝是传说的。

这个分析显示,龙类型和超能 (Psychic) 类型的神奇宝贝更有可能是传说的神奇宝贝,而普通类型、毒 (Poison) 类型和虫 (Bug) 类型的神奇宝贝作为传说的可能性相对较低。

接下来,我们将解决最后一个问题。

问题6: 你能组建一个神奇宝贝梦之队吗?一个由6只神奇宝贝组成的队伍,能够造成最大的伤害,同时对其他任何6只神奇宝贝的队伍都相对不受伤害。

这是一个相当复杂的问题,因为它涉及到神奇宝贝之间的相互作用、属性匹配等。一个简化的方法是选择那些具有最高总属性值的神奇宝贝,并考虑他们的属性组合来确保队伍的多样性。

让我们首先找出具有最高总属性值的神奇宝贝。

# Find the top 6 Pokemon with the highest total stats
top_6_pokemon = pokemon_df.sort_values(by='total_stats', ascending=False).head(6)

top_6_pokemon[['name''type1''type2''total_stats']]

基于总属性值,以下是六只神奇宝贝的“梦之队”:

  • Mewtwo (超能类型) - 总属性值: 780
  • Rayquaza (龙/飞行类型) - 总属性值: 780
  • Groudon (地面类型) - 总属性值: 770
  • Kyogre (水类型) - 总属性值: 770
  • Arceus (普通类型) - 总属性值: 720
  • Zygarde (龙/地面类型) - 总属性值: 708

这个队伍有一个广泛的属性组合,这有助于确保它能够对抗各种类型的敌人。然而,请记住,这只是一个基于总属性值的简化选择。实际的战斗效果还取决于神奇宝贝的技能、策略和相互之间的匹配。

更复杂一些的模型:

建立一个神奇宝贝的“梦之队涉及到多个考虑因素,包括每个神奇宝贝的总属性值、与其他神奇宝贝的相对优势、属性匹配等。为了解决这个问题,我们可以尝试创建一个整数线性规划模型。

符号定义:

  • : 神奇宝贝的索引。
  • : 神奇宝贝的索引(用于表示另一个神奇宝贝)。
  • : 一个二进制决策变量,表示是否选择神奇宝贝 。如果选择,则 ,否则
  • : 神奇宝贝 的总属性值。
  • : 神奇宝贝 对神奇宝贝 的伤害系数。 数学模型: 目标函数:

约束条件:

  1. 只能选择6只神奇宝贝:
  1. 二进制决策变量约束:

目标函数旨在最大化我们选择的神奇宝贝的总属性值,同时考虑神奇宝贝之间的匹配优势。第一 个项 旨在最大化我们队伍的总属性值。第二个项 考虑我 们选择的神奇宝贝对其他末被选择的神奇宝贝的优势。 这只是一个基础模型。实际上,为了得到一个真正的“梦之队”,我们可能需要考虑更多的约束 和细节,例如确保队伍有多样性、考虑特定技能和策略等。

求解上述数学模型需要使用整数线性规划 (ILP) 方法。但首先,我们需要构建伤害系数 。 这需要根据属性相互作用的规则来确定。我们可以使用数据集中的“against_?”列来为每一 种类型计算伤害系数。

但在这之前,考虑到该模型的是杂性和计算需求,我们简化问题,例如,我们可以首先只考虑主要类型 ('type1') 的相互作用,并使用总属性值作为 。这样,我们可以得到一个较 为简化但仍然有指导意义的解。 接下来,我们开始创建伤害系数矩阵

# Create a damage coefficient matrix D based on primary type interactions
types = pokemon_df['type1'].dropna().unique()
n = len(pokemon_df)
D = pd.DataFrame(1, index=pokemon_df.index, columns=pokemon_df.index)  # Initialize with 1s


# Handling missing damage coefficients by setting them to 1 (neutral interaction)
for i in pokemon_df.index:
    for j in pokemon_df.index:
        if i != j:
            attacker_type = pokemon_df.loc[i, 'type1']
            column_name = f'against_{attacker_type}'
            if column_name in pokemon_df.columns:
                damage_coefficient = pokemon_df.loc[j, column_name]
                D.at[i, j] = damage_coefficient
            else:
                D.at[i, j] = 1  # Set to 1 if missing

D.head()

我们已成功创建了伤害系数矩阵 。现在,我们可以使用整数线性规划 (ILP) 来解决该模型。 考虑到这是一个计算密集型任务,尤其是考虑到我们有 800 多个神奇宝贝,我们将采用一个启发式的方法: 我们首先将神奇宝贝按其总属性值进行排序,然后只选择前100名进行计算,以减少计算的复杂性。

import numpy as np
from scipy.optimize import linprog
# Retrieve S again since it was defined earlier
S = pokemon_df['total_stats']

# Extract subset for top 100 Pokemon
S_subset = S[top_100_pokemon]

# Create the coefficients for the objective function
coeff = list(S_subset) + list(D_subset.values.flatten())

# Constraints
A_eq = np.zeros((len(top_100_pokemon), len(coeff)))
for i in range(len(top_100_pokemon)):
    A_eq[i, i] = 1

b_eq = np.ones(len(top_100_pokemon)) * 6

# Bounds for each variable: 0 <= x <= 1
x0_bounds = (01)
bounds = [x0_bounds] * len(coeff)

# Solve the ILP
result = linprog(c=-np.array(coeff),  # We negate because linprog tries to minimize, not maximize
                 A_eq=A_eq,
                 b_eq=b_eq,
                 bounds=bounds,
                 method='simplex')

selected_indices = [i for i, value in enumerate(result.x[:100]) if value > 0.5]
selected_pokemon = pokemon_df.loc[top_100_pokemon].iloc[selected_indices]

selected_pokemon[['name''type1''total_stats']]

启发式算法是一种找到问题的近似解的方法,特别是当精确解决问题非常困难或时间消耗太大时。为了解决上述问题,我会采用以下简化的“贪心”策略:

  • 从具有最高总属性值的神奇宝贝开始。
  • 选择下一个神奇宝贝,该神奇宝贝与已选的神奇宝贝组合可以造成最大的伤害,同时最小化接收的伤害。
  • 重复第2步,直到选择了6只神奇宝贝。 这种方法可能不会得到全局最优解,但应该可以得到一个不错的解。

让我们尝试使用这种贪心策略。

def greedy_team_selection(pokemon_df, D, n=6):
    # Start with the Pokemon with the highest total stats
    selected_indices = [pokemon_df['total_stats'].idxmax()]

    for _ in range(n - 1):
        best_next_index = -1
        best_next_value = -float('inf')

        for i in pokemon_df.index:
            if i not in selected_indices:
                current_value = 0
                # Consider damage inflicted to others and damage taken from others
                for j in selected_indices:
                    current_value += D.loc[i, j] - D.loc[j, i]
                
                # Also consider the total stats of the Pokemon
                current_value += pokemon_df.loc[i, 'total_stats']

                if current_value > best_next_value:
                    best_next_value = current_value
                    best_next_index = i

        selected_indices.append(best_next_index)

    return selected_indices

selected_indices_greedy = greedy_team_selection(pokemon_df, D)
selected_pokemon_greedy = pokemon_df.loc[selected_indices_greedy]

selected_pokemon_greedy[['name''type1''total_stats']]

使用含心启发式策略,我们得到了以下的神奇宝贝“梦之队”:

  1. Mewtwo (超能类型) - 总属性值: 780
  2. Rayquaza (龙类型) - 总属性值: 780
  3. Kyogre (水类型) - 总属性值: 770
  4. Groudon (地面类型) - 总属性值: 770
  5. Arceus (普通类型) - 总属性值: 720
  6. Zygarde (龙类型) - 总属性值: 708

这与我们之前基于总属性值直接选择的队伍稍有不同(三四名互换了位置),但是这次我们还考虑了神奇宝贝之间的相互作用,以及它们与其他神奇宝贝的相对优势。需要注意的是,这只是一个近似解,可能不是全局最优解。但是,它为我们提供了一个合理 的、基于数据的神奇宝贝队伍建议。

我们可以尝试使用模拟退火(Simulated Annealing)算法,这是一种广泛用于优化问题的启发式方法。模拟退火算法的基本思想是从一个初始解开始,然后在解空间中随机选择一个邻近解,如果新解比当前解更好,或者满足某个准则,那么就接受这个新解。该算法重复这个过程,但随着时间的推移,接受劣解的可能性会逐渐减小,直到算法收敛。 具体地

  • 初始化:选择前6个总属性值最高的宝可梦作为初始解。
  • 迭代:从当前队伍中随机选择一个宝可梦,并用另一个未被选择的宝可梦替换它,从而得到一个新的队伍。
  • 决策:如果新队伍比当前队伍更好(即造成的伤害更大或受到的伤害更小),则接受新队伍;否则,以某个概率接受新队伍。
  • 降温:随着迭代次数的增加,接受劣解的概率逐渐减小。
  • 终止:当达到最大迭代次数或温度低于某个阈值时,算法终止。
import random
import math
def simulated_annealing(pokemon_df, D, max_iter=10000, initial_temp=100, alpha=0.995, stop_temp=0.1):
    # Utility function to evaluate the quality of a team
    def evaluate_team(team_indices):
        total_damage = sum(pokemon_df.loc[idx, 'total_stats'for idx in team_indices)
        for i in team_indices:
            for j in team_indices:
                if i != j:
                    total_damage += D.loc[i, j] - D.loc[j, i]
        return total_damage

    # Initial solution: Top 6 Pokemon based on total stats
    current_team = list(pokemon_df.sort_values(by='total_stats', ascending=False).head(6).index)
    current_value = evaluate_team(current_team)

    best_team = current_team.copy()
    best_value = current_value

    temp = initial_temp

    for iteration in range(max_iter):
        if temp < stop_temp:
            break

        # Randomly select a Pokemon from the current team
        swap_out_index = random.choice(current_team)

        # Randomly select a Pokemon not in the current team
        swap_in_index = random.choice(pokemon_df.index.difference(current_team))

        # Create a new team with the swap
        new_team = current_team.copy()
        new_team.remove(swap_out_index)
        new_team.append(swap_in_index)

        # Evaluate the new team
        new_value = evaluate_team(new_team)

        # Decision logic
        if new_value > current_value or random.random() < math.exp((new_value - current_value) / temp):
            current_team, current_value = new_team, new_value

        # Update the best solution
        if current_value > best_value:
            best_team, best_value = current_team, current_value

        # Cooling schedule
        temp *= alpha

    return best_team
# Apply simulated annealing
best_team_indices = simulated_annealing(pokemon_df, D)
best_team = pokemon_df.loc[best_team_indices]
best_team[['name''type1''total_stats']]

虽然上述计算结果位次稍有差别,但我们的神奇宝贝战队成员还是不变的,他们就是:

  1. Mewtwo (超能类型) - 总属性值: 780
  2. Rayquaza (龙类型) - 总属性值: 780
  3. Kyogre (水类型) - 总属性值: 770
  4. Groudon (地面类型) - 总属性值: 770
  5. Arceus (普通类型) - 总属性值: 720
  6. Zygarde (龙类型) - 总属性值: 708

来张合影吧:

结语

经过一系列计算和分析,我们得到了一个“梦之队”,由Mewtwo、Rayquaza、Groudon、Kyogre、Arceus和Zygarde组成。这些神奇宝贝不仅属性强大,而且在相互作用上也表现出色。虽然数学为我们提供了一个理论上的最优解,但真正的神奇宝贝战斗还取决于策略、技能和一点点运气。但无论如何,这次的探索证明了一点:数学和数据分析可以为我们的冒险带来新的视角和洞见。下次,当你在考虑你的下一个神奇宝贝队伍时,也许可以考虑加入一点数学思考!


没想到分析了这么久,虽然有chatgpt的帮忙,但还是花了不少时间,感兴趣的朋友欢迎点个赞啊


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存