2025美赛数学建模c题思路+模型+代码分享!非机构不卖课(12:51已更新完善Q1模型的代码)

2025 MCM C 题思路分析

2025美赛数学建模c题思路+模型+代码分享!非机构不卖课(12:51已更新完善Q1模型的代码)_第1张图片
中文版题目翻译在这里先不放了,重点说一下我和队友讨论出来的一个简单思路。

题目背景信息

  • 排名、金牌、奖牌数量: 奥运会奖牌榜的核心指标。
  • 奖牌预测方法: 强调基于参赛运动员名单而非历史奖牌数据进行预测。
  • 数据限制: 模型和分析必须仅使用提供的五个数据文件,所以好好想想到时候伟大教练应该怎么考虑 (data_dictionary.csv, summerOly_athletes.csv, summerOly_medal_counts.csv, summerOly_hosts.csv, summerOly_programs.csv)。

名词解释

  • discipline (赛类): 如游泳、田径等大的运动类别。
  • event (赛项): 具体比赛项目,如男子100米自由泳,是产生奖牌的具体赛事。

问题分解与建模思路

Q1 (Model 1): 奖牌预测模型

目标: 为每个国家建立奖牌预测模型,至少预测金牌和总奖牌数,并给出预测的置信区间,评估模型性能。

输入: (至少)一个字典,key 为运动员名称,value 为运动员的过往竞赛数据。

输出: 一个字典,key 为运动员名称,value 为预测的该运动员获得的奖牌数量(可以是单个数值或一个概率分布)。

核心: 研究运动员和奖牌之间的关系。

关键词: athletes, medal counts, gold medal, quantification, mathematical modeling.

参考论文:

  • 论文1: Olympic Game Medal Count Analysis (calstate.edu) - 分析了奖牌与温度、GDP 的关系,但未分析运动员与奖牌的关系,可参考其分析方法。
  • 论文2: Forecasting the Olympic medal distribution – A socioeconomic machine learning model - ScienceDirect - 未分析运动员与奖牌关系,但对结果的预测有参考价值,模型需谨慎借鉴,不要使用额外数据,额外数据根据题目要求只能作为佐证。

模型建议:

  • 尽量使用随机森林及其衍生模型。
  • 创新点: 可探索随机森林的衍生模型,但避免过于复杂,保证实现可行性。
  • 模型性能评估: 使用适当的评估指标(如 MSE, RMSE, R^2),进行交叉验证。
Q1.1: 2028 年洛杉矶奥运会预测

2025美赛数学建模c题思路+模型+代码分享!非机构不卖课(12:51已更新完善Q1模型的代码)_第2张图片

目标: 基于 Q1 模型,预测 2028 年洛杉矶奥运会的奖牌榜,包括预测区间,并分析哪些国家可能进步或退步。

输出:

  • 预测的 2028 年奥运会奖牌榜 (包括区间)
  • 哪些国家可能进步/退步的分析

核心: 应用已建立的奖牌预测模型进行预测。

Q1.2: 未获奖牌国家首次获奖时间预测

目标: 模型需包括未获奖牌国家,预测多少国家在下届奥运会首次获奖,并给出概率。

输入: 一个字典,每个 key 为运动员,每个 value 为运动员的过往竞赛记录。

输出:

  • 一个字典,key 为运动员,value 为运动员获得奖牌的数量(或概率分布)。
  • 未获奖牌国家首次获奖预测的概率。

理解: 将模型准确率视为预测的可能性。

核心: 分析运动员参赛经历、奖牌记录与首次获奖之间的关系。

Q1.3: 赛事类型与奖牌关系

目标: 探索赛事类型(如游泳、举重)和国家奖牌数之间的关系,分析哪些体育项目对不同国家重要,以及主办国选择如何影响结果。

输入: 对于每个国家,赛事类型 (x)。

输出: 对于每个国家,奖牌数量 (y)。

方法:

  • 尝试多种机器学习模型(如回归、树模型),对比结果,选择最优模型。
  • 模型建立过程可仅针对最优模型详细描述。

核心: 揭示赛事类型对国家奖牌数的潜在影响。

当然可以,我们先从 Q1 的模型开始,一步一步来完成代码。请确保你已经安装了 pandasscikit-learn 库。

代码在这里!!!!!!!!Q1:建立奖牌预测模型

Q1 完整解答:模型开发、不确定性评估和性能衡量

目标: 开发一个更完善的奖牌预测模型,并包含不确定性估计和性能评估。

改进方向:

  1. 更丰富的特征工程: 加入历史奖牌表现作为特征,例如过去几届奥运会的平均金牌数、总奖牌数。
  2. 不确定性估计: 使用 Bootstrap 方法来估计预测结果的不确定性,并给出预测区间。
  3. 性能衡量: 继续使用 MSE 和 R^2,并考虑添加其他指标,例如平均绝对误差 (MAE)。

代码实现:

步骤 1: 扩展特征工程 - 加入历史奖牌特征

我们在特征中加入过去几届奥运会的金牌和总奖牌数均值,以捕捉国家历史奖牌表现的趋势。

import pandas as pd
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error, r2_score
import numpy as np

# 加载数据 (保持之前的数据加载和清洗代码不变)
athletes_df = pd.read_csv('summerOly_athletes.csv', encoding='utf-8')
medal_counts_df = pd.read_csv('summerOly_medal_counts.csv', encoding='utf-8')
medal_counts_df = medal_counts_df[~medal_counts_df['NOC'].isin(['Mixed team', 'ANZ'])]
medal_counts_df['Year'] = medal_counts_df['Year'].astype(int)
athletes_df['Year'] = athletes_df['Year'].astype(int)


# 特征工程 -  加入历史奖牌特征
def create_historical_features(df, years_ago_list=[4, 8, 12]): #  考虑过去 4, 8, 12 年的奥运会
    df_features = df.copy()
    for years_ago in years_ago_list:
        df_shifted = df.copy()
        df_shifted['Year'] = df_shifted['Year'] + years_ago #  年份向前平移
        df_shifted = df_shifted[['Year', 'NOC', 'Gold', 'Total']] #  只保留需要的列
        df_shifted.rename(columns={'Gold': f'Gold_Past_{years_ago}Y', 'Total': f'Total_Past_{years_ago}Y'}, inplace=True) #  重命名列名
        df_features = pd.merge(df_features, df_shifted, on=['Year', 'NOC'], how='left') #  左连接合并
    return df_features

medal_counts_featured_df = create_historical_features(medal_counts_df)

# 填充缺失值 (历史数据可能缺失,用 0 填充)
medal_counts_featured_df.fillna(0, inplace=True)

# 准备训练数据 (与之前的代码基本相同,但使用新的特征数据集)
features = ['Year', 'Gold_Past_4Y', 'Total_Past_4Y', 'Gold_Past_8Y', 'Total_Past_8Y', 'Gold_Past_12Y', 'Total_Past_12Y'] #  加入历史奖牌特征
target_gold = 'Gold'
target_total = 'Total'

data = medal_counts_featured_df[['Year', 'NOC', 'Gold', 'Total'] + features[1:]].copy() #  选择需要的列
data = pd.get_dummies(data, columns=['NOC']) # One-Hot 编码

train_data = data[data['Year'] < 2024].copy()
test_data = data[data['Year'] == 2024].copy()

X_train = train_data.drop([target_gold, target_total], axis=1)
y_gold_train = train_data[target_gold]
y_total_train = train_data[target_total]

X_test = test_data.drop([target_gold, target_total], axis=1)
y_gold_test = test_data[target_gold]
y_total_test = test_data[target_total]


print("\n特征工程后的训练特征 (X_train) 前几行:")
print(X_train.head())

代码解释 - 特征工程改进:

  1. create_historical_features 函数:

    • 输入: 奖牌计数 DataFrame (df) 和要考虑的过去奥运会年份列表 (years_ago_list)。
    • 功能:
      • 循环遍历 years_ago_list 中的每个年份 (例如 4, 8, 12 年)。
      • 对于每个年份,将原始 DataFrame (df) 复制一份 (df_shifted)。
      • df_shifted 的 ‘Year’ 列向前平移 years_ago 年,例如,如果 years_ago 是 4,则 1996 年的数据会变成 2000 年的 “过去 4 年数据”。
      • 重命名 df_shifted 的 ‘Gold’ 和 ‘Total’ 列,添加 _Past_{years_ago}Y 后缀,例如 Gold_Past_4Y
      • 使用 ‘Year’ 和 ‘NOC’ 列将 df_featuresdf_shifted 进行左连接合并 (pd.merge)。左连接保证所有原始数据行都保留,即使没有对应的历史数据(对于早期的奥运会)。
    • 输出: 添加了历史奖牌特征的新 DataFrame (df_features)。
  2. 调用 create_historical_features:

    • medal_counts_featured_df = create_historical_features(medal_counts_df): 对原始 medal_counts_df 应用特征工程函数。
  3. 填充缺失值:

    • medal_counts_featured_df.fillna(0, inplace=True): 由于左连接,对于早期奥运会年份,可能没有过去 4, 8, 12 年的数据,会产生缺失值 (NaN)。使用 0 填充这些缺失值,表示在奥运会历史早期,没有更早的奖牌数据。
  4. 更新特征列表:

    • features = ['Year', 'Gold_Past_4Y', 'Total_Past_4Y', ..., 'Total_Past_12Y']: 将新创建的历史奖牌特征添加到特征列表中。
  5. 数据准备: 后续的数据准备代码与之前基本相同,但现在使用的是 medal_counts_featured_df 这个包含了更多特征的数据集。

步骤 2: 模型训练和评估

# 模型训练 - 随机森林回归 (代码与之前相同)
model_gold = RandomForestRegressor(random_state=42)
model_total = RandomForestRegressor(random_state=42)

model_gold.fit(X_train, y_gold_train)
model_total.fit(X_train, y_total_train)

# 模型预测 (代码与之前相同)
y_gold_pred = model_gold.predict(X_test)
y_total_pred = model_total.predict(X_test)

# 模型评估 (代码与之前相同)
mse_gold = mean_squared_error(y_gold_test, y_gold_pred)
r2_gold = r2_score(y_gold_test, y_gold_pred)
mse_total = mean_squared_error(y_total_test, y_total_pred)
r2_total = r2_score(y_total_test, y_total_pred)

print("\n金牌数模型评估 (更新特征后):")
print(f"均方误差 (MSE): {mse_gold:.2f}")
print(f"R 平方值 (R^2): {r2_gold:.2f}")

print("\n总奖牌数模型评估 (更新特征后):")
print(f"均方误差 (MSE): {mse_total:.2f}")
print(f"R 平方值 (R^2): {r2_total:.2f}")

步骤 3: 预测不确定性 - Bootstrap 方法

我们使用 Bootstrap 方法来估计预测结果的不确定性,并计算 95% 的预测区间。

def bootstrap_predict(model, X_test, n_bootstrap=1000): #  Bootstrap 预测函数
    predictions = []
    for _ in range(n_bootstrap):
        # 从训练数据集中有放回地抽样
        indices = np.random.choice(len(X_train), len(X_train), replace=True)
        X_sample = X_train.iloc[indices]
        y_sample_gold = y_gold_train.iloc[indices]
        y_sample_total = y_total_train.iloc[indices]

        # 训练模型
        model_sample_gold = RandomForestRegressor(random_state=42) #  每次 bootstrap 训练一个新的模型
        model_sample_total = RandomForestRegressor(random_state=42)
        model_sample_gold.fit(X_sample, y_sample_gold)
        model_sample_total.fit(X_sample, y_sample_total)

        # 预测测试集
        y_pred_gold_bootstrap = model_sample_gold.predict(X_test)
        y_pred_total_bootstrap = model_sample_total.predict(X_test)
        predictions.append(np.column_stack((y_pred_gold_bootstrap, y_pred_total_bootstrap))) #  保存每次 bootstrap 的预测结果

    predictions = np.concatenate(predictions, axis=0) #  将所有 bootstrap 的预测结果合并
    return predictions


bootstrap_preds = bootstrap_predict(RandomForestRegressor(random_state=42), X_test) #  调用 bootstrap 预测函数

# 计算预测区间 (95% 置信区间)
lower_percentile = 2.5
upper_percentile = 97.5

y_gold_pred_lower = np.percentile(bootstrap_preds[:, 0], lower_percentile, axis=0) #  金牌数预测区间下界
y_gold_pred_upper = np.percentile(bootstrap_preds[:, 0], upper_percentile, axis=0) #  金牌数预测区间上界
y_total_pred_lower = np.percentile(bootstrap_preds[:, 1], lower_percentile, axis=0) #  总奖牌数预测区间下界
y_total_pred_upper = np.percentile(bootstrap_preds[:, 1], upper_percentile, axis=0) #  总奖牌数预测区间上界


# 查看带预测区间的结果
predictions_df_with_interval = pd.DataFrame({
    'Actual_Gold': y_gold_test,
    'Predicted_Gold': y_gold_pred.round(0),
    'Gold_Lower_95CI': y_gold_pred_lower.round(0),
    'Gold_Upper_95CI': y_gold_pred_upper.round(0),
    'Actual_Total': y_total_test,
    'Predicted_Total': y_total_pred.round(0),
    'Total_Lower_95CI': y_total_pred_lower.round(0),
    'Total_Upper_95CI': y_total_pred_upper.round(0)
}, index = test_data.filter(like='NOC_').columns.str.replace('NOC_', '')) # 使用 One-Hot 编码后的 NOC 列名作为索引,并去除前缀

print("\n2024 年奖牌预测结果 (部分国家) - 带 95% 预测区间:")
print(predictions_df_with_interval.head(10))

代码解释 - Bootstrap 预测不确定性:

  1. bootstrap_predict 函数:

    • 输入: 模型 (model),测试集特征 (X_test),Bootstrap 迭代次数 (n_bootstrap)。
    • 功能:
      • 循环 n_bootstrap 次 (例如 1000 次)。
      • 在每次迭代中,从训练数据集 (注意是训练集) 中有放回地随机抽样,生成一个 Bootstrap 样本。
      • 使用 Bootstrap 样本重新训练一个新的随机森林模型 (model_sample_gold, model_sample_total)。
      • 使用新训练的模型预测测试集 X_test
      • 将每次 Bootstrap 预测的金牌数和总奖牌数保存起来。
    • 输出: 一个 NumPy 数组 (predictions),形状为 (n_bootstrap * len(X_test), 2),其中每一行是每次 Bootstrap 迭代对所有测试样本的金牌数和总奖牌数的预测结果。
  2. 调用 bootstrap_predict:

    • bootstrap_preds = bootstrap_predict(...): 调用 bootstrap_predict 函数,得到 Bootstrap 预测结果。
  3. 计算预测区间:

    • lower_percentile = 2.5, upper_percentile = 97.5: 设置置信区间的上下界百分位数 (95% 置信区间)。
    • y_gold_pred_lower = np.percentile(...), y_gold_pred_upper = np.percentile(...): 使用 np.percentile 函数,分别计算金牌数和总奖牌数在所有 Bootstrap 预测结果中的下界 (2.5% 分位数) 和上界 (97.5% 分位数)。
  4. 创建带预测区间的 DataFrame:

    • predictions_df_with_interval = pd.DataFrame(...): 创建一个新的 DataFrame,除了实际值和点预测值外,还包括金牌数和总奖牌数的 95% 预测区间的上下界。
    • index = test_data.filter(like='NOC_').columns.str.replace('NOC_', ''): 使用 One-Hot 编码后的 NOC 列名作为索引,并去除 ‘NOC_’ 前缀,使索引更清晰。
  5. 打印带预测区间的预测结果: 打印包含预测区间的新 DataFrame 的前几行。

运行完整代码:

现在运行完整的代码,你将得到:

  • 加入了历史奖牌特征的模型评估结果 (MSE, R^2)。
  • 2024 年部分国家的金牌数和总奖牌数预测结果,以及对应的 95% 预测区间。

解答 Q1:

至此,我们已经完成了解答 Q1 的主要部分:

  • 模型开发: 我们使用随机森林回归模型,并加入了历史奖牌特征,提高了模型的预测能力。
  • 不确定性评估: 使用 Bootstrap 方法估计了预测结果的不确定性,并给出了 95% 的预测区间。
  • 性能衡量: 通过 MSE 和 R^2 等指标评估了模型的性能。

请尝试运行这段代码,并根据输出结果进行分析和调整。 接下来我们会继续更新 Q1.1, Q1.2 等问题的代码实现。

Q2: 教练效应分析

2025美赛数学建模c题思路+模型+代码分享!非机构不卖课(12:51已更新完善Q1模型的代码)_第3张图片

目标: 分析教练对国家奖牌数的影响,量化这种效应,并为三个国家挑选合适的运动项目引入“优秀教练”。

问题:

  • 第一: 量化教练对奖牌数量的提升效果。
  • 第二: 为三个国家选择最应该引入“优秀教练”的运动项目(选择运动员质量高,但奖牌数少的项目)。

建模思路 (推荐第二种):

  1. 建立回归模型: 不加入教练项,用已有数据建立一个基准模型。
  2. 分析模型偏差: 如果预测结果出现显著偏差(误差显著性分析),则表明可能存在其他影响因素(如“优秀教练”)。
  3. 验证偏差年份: 检查误差显著的年份,是否与“优秀教练”的引入时间相符(例如,中国女排或题目中提及的教练案例)。
  4. 量化“优秀教练”效应: 如果误差年份与教练变动匹配,则可认为教练因素影响明显。可以通过对比有无教练时的误差大小来估计教练带来的影响。

核心: 通过模型误差分析间接推断教练的作用。

Q3: 额外见解

2025美赛数学建模c题思路+模型+代码分享!非机构不卖课(12:51已更新完善Q1模型的代码)_第4张图片

目标: 挖掘关于奥运奖牌数的其他原创见解,并解释如何帮助国家奥委会。

思路:

  • 在模型建立、计算、文献搜索过程中,发掘有价值的衍生见解。
  • 偏向于语文建模和故事讲述,可联系 Q1.3 分析,提出新的见解。

核心: 从数据中挖掘除了直接预测以外的其他有用信息。

总结

  • 模型选择: 使用随机森林及其衍生模型。
  • 数据限制: 严格遵守只能使用提供的数据集。
  • 深入分析: 不仅要进行预测,还要分析预测结果背后的原因和影响。
  • 团队合作: 分工明确,协同完成。奥利给加油xdm!

你可能感兴趣的:(机器学习,人工智能,数学建模,大数据,python)