当大家面临着复杂的数学建模问题时,你是否曾经感到茫然无措?作为2022年美国大学生数学建模比赛的O奖得主,我为大家提供了一套优秀的解题思路,让你轻松应对各种难题。
让我们来看看美赛的C题!
完整内容可以在文章末尾领取!
问题重述
问题重述:
在2023年温布尔登男子单打决赛中,20岁的西班牙新星卡洛斯·阿尔卡拉斯击败了36岁的诺瓦克·德约科维奇。这场比赛是德约科维奇自2013年以来在温网的首次败北,结束了这位历史上一位伟大选手在大满贯比赛中的非凡表现。
比赛本身是一场激动人心的战斗。德约科维奇在第一盘中占据绝对优势,以6-1(赢得7局中的6局)取胜。然而,第二盘紧张而最终由阿尔卡拉斯在抢七局中以7-6获胜。第三盘与第一盘相反,阿尔卡拉斯轻松以6-1获胜。年轻的西班牙人在第四盘开始时似乎完全掌控比赛,但比赛再次改变方向,德约科维奇完全掌控比赛以6-3获胜。第五盘开始时,德约科维奇带着第四盘的优势,但比赛再次改变方向,阿尔卡拉斯掌控比赛并以6-4获胜。本问题提供了这场比赛的数据集“match_id”为“2023-wimbledon-1701”。
在这场比赛中,经常发生明显的变化,有时是在某个选手占据优势的情况下,甚至会影响多个积分或局数,这经常被归因于“动力”现象。动量的一个词典定义是“通过运动或一系列事件获得的力量或力量”。在体育中,一支团队或球员可能会感到他们在比赛/局中有动力,但要测量这种现象是困难的。此外,很难立即看出比赛中的各种事件如何影响或改变动力(如果存在的话)。
提供了温网2023男子比赛后两轮的所有积分数据。你可以选择包含额外的球员信息或其他数据,但必须完全记录来源。使用数据来:
- 开发一个模型,捕捉比赛进行时积分的流动,并将其应用于一场或多场比赛。你的模型应该能够确定在比赛的某个时刻哪位球员表现更好,以及他们的表现有多好。提供基于你的模型的可视化,以描绘比赛的流动。注意:在网球中,发球方赢得积分/局的概率要高得多。你可能希望以某种方式将这一点纳入你的模型。
- 一个网球教练怀疑“动量”在比赛中没有起到任何作用。相反,他提出说球员之间的表现波动和成功的连续是随机的。使用你的模型/度量来评估这一说法。
- 教练们希望知道是否有指标可以帮助确定比赛的进行何时从一个球员转向另一个球员。使用至少一场比赛提供的数据,开发一个能够预测比赛中这些波动的模型。哪些因素似乎与此相关(如果有的话)?
- 在过去的比赛“动量”波动差异的基础上,你会如何建议一名球员参加与不同球员的新比赛?
- 测试你在一个或多个其他比赛上开发的模型。你的模型在预测比赛波动方面表现如何?如果模型在某些时候表现不佳,你能否确定可能需要在未来的模型中包含的任何因素?你的模型对其他比赛(如女子比赛)、锦标赛、球场表面和其他体育(如乒乓球)有多通用?
- 生成一份不超过25页的报告,总结你的发现,并包含一份一到两页的备忘录,概括你的结果并为教练提供建议,关于“动量”的作用,以及如何准备球员应对影响比赛进行中的事件。
问题一
-
积分计算:
-
局和积分规则: 在网球比赛中,每场比赛包含多个局(sets),每个局包含多个游戏(games),每个游戏包含多个积分(points)。玩家必须以2分的优势赢得游戏和局。积分的计数方式是0、15、30、40,胜出的情况称为“Deuce”,之后再赢一个积分即可获胜。在抢七局中,需要先达到7分,必须以至少2分的优势获胜。
-
球员得分记录: 根据提供的数据集,可以追踪每个球员在比赛中的得分情况,包括每个局、每个游戏和每个积分的得分。
-
-
动量模型:
-
滑动窗口计算动量: 为了计算动量的变化,引入一个滑动窗口,窗口内包含一定数量的连续积分。可以选择合适的窗口大小,比如每个局结束时或每个游戏结束时。在每个窗口内,计算球员得分的变化,并根据变化来计算动量。
-
动量公式: 动量(Momentum)可以使用得分变化与时间变化的比率来表示,即 M = Δ S Δ t M = \frac{\Delta S}{\Delta t} M=ΔtΔS,其中 Δ S \Delta S ΔS为得分变化, Δ t \Delta t Δt为时间变化。
-
-
发球优势的影响:
-
引入发球优势因子: 考虑到网球中发球方有更高的概率赢得积分,引入一个发球优势因子 F F F。根据发球方和非发球方的得分变化来调整动量模型中的得分变化。
-
公式调整: 对于发球方得分变化 Δ S 1 \Delta S1 ΔS1,可以使用 Δ S 1 = Δ S 1 + F ⋅ 发球方得分变化 \Delta S1 = \Delta S1 + F \cdot \text{发球方得分变化} ΔS1=ΔS1+F⋅发球方得分变化,对于非发球方得分变化 Δ S 2 \Delta S2 ΔS2,可以使用 Δ S 2 = Δ S 2 + F ⋅ 非发球方得分变化 \Delta S2 = \Delta S2 + F \cdot \text{非发球方得分变化} ΔS2=ΔS2+F⋅非发球方得分变化。
-
-
可视化:
-
动量图和得分变化曲线: 利用得到的动量数据和得分变化数据,可以生成动量图和得分变化曲线。这些图表可以帮助教练和球员更直观地了解比赛中的动态变化。
-
其他可视化工具: 根据需要,还可以考虑使用其他可视化工具,比如热力图来表示不同时间段的动量强度。
-
import pandas as pd
import matplotlib.pyplot as plt# 读取数据集
data = pd.read_csv("Wimbledon_featured_matches.csv")# 初始化变量
momentum_data = [] # 存储动量数据
window_size = 5 # 滑动窗口大小# 遍历每个比赛点
for i in range(len(data)):# 获取当前比赛点的信息match_id = data.loc[i, 'match_id']elapsed_time = data.loc[i, 'elapsed_time']player1_score = data.loc[i, 'p1_points_won']player2_score = data.loc[i, 'p2_points_won']server = data.loc[i, 'server']# 计算得分差和动量score_diff = player1_score - player2_scoremomentum = score_diff / window_size# 考虑发球优势if server == 1: # 如果是发球方momentum += 0.1 * (data.loc[i, 'p1_points_won'] - data.loc[i, 'p1_points_won_prev'])else: # 如果是非发球方momentum += 0.1 * (data.loc[i, 'p2_points_won'] - data.loc[i, 'p2_points_won_prev'])# 将动量数据添加到列表中momentum_data.append({'match_id': match_id, 'elapsed_time': elapsed_time, 'momentum': momentum})# 更新前一点的得分,用于下一个数据点的发球优势计算data.at[i, 'p1_points_won_prev'] = player1_scoredata.at[i, 'p2_points_won_prev'] = player2_score# 将动量数据转换为DataFrame
momentum_df = pd.DataFrame(momentum_data)# 可视化动量变化
plt.figure(figsize=(12, 6))
plt.plot(momentum_df['elapsed_time'], momentum_df['momentum'], label='Momentum', color='blue')
plt.title('Momentum in Tennis Match')
plt.xlabel('Elapsed Time (minutes)')#见完整版
问题二
1. 数据准备和理解:
- 数据探索: 仔细研究提供的“2023-wimbledon-1701”比赛数据,了解数据结构、特征和标签。
- 数据清理: 处理缺失值、异常值,并确保数据格式一致。
2. 建立基准模型:
- 基准模型选择: 建立一个简单的基准模型,假设球赛中的成功或失败是随机的。可以计算每个球员在比赛中的平均胜率作为基准。
3. 特征工程:
- 动量特征提取: 根据问题描述,计算每个点之前的动量。可以考虑使用球员最近几个点或游戏的胜负情况来衡量动量。
- 其他特征选择: 考虑其他可能影响球员表现的特征,如发球成功率、接发球成功率、比赛场地等。
4. 模型选择和建立动量模型:
- 机器学习模型选择: 考虑使用逻辑回归等分类模型,以预测球员在某一点或游戏中的成功或失败。
- 模型建立: 使用选定的模型建立动量模型,其中动量特征和其他特征作为输入。
逻辑回归模型公式:
P ( Player1 Wins ) = 1 1 + e − ( β 0 + β 1 ⋅ Momentum + β 2 ⋅ Other Features ) P(\text{{Player1 Wins}}) = \frac{1}{1 + e^{-(\beta_0 + \beta_1 \cdot \text{{Momentum}} + \beta_2 \cdot \text{{Other Features}})}} P(Player1 Wins)=1+e−(β0+β1⋅Momentum+β2⋅Other Features)1
其中, Momentum \text{{Momentum}} Momentum 表示在该点之前的动量, Other Features \text{{Other Features}} Other Features 是其他可能影响球员表现的特征。模型的参数 β 0 , β 1 , β 2 \beta_0, \beta_1, \beta_2 β0,β1,β2 需要从训练数据中学习得到。
5. 模型训练和调优:
- 训练集和测试集划分: 将数据划分为训练集和测试集,用于模型的训练和验证。
- 模型训练: 使用训练集对模型进行训练,并调整模型参数以提高性能。
6. 模型验证和性能评估:
- 基准模型验证: 验证基准模型的预测准确性,作为比较的基准。
- 动量模型验证: 验证动量模型在测试集上的性能,比较其与基准模型的差异。
- 性能评估: 使用准确性、精确度、召回率等指标对模型进行评估。
7. 特征重要性分析:
- 分析特征的重要性: 对动量模型中的特征进行分析,了解哪些因素对于模型的性能贡献最大。
8. 结论和建议:
- 问题回答: 结合基准模型和动量模型的分析,回答教练提出的问题,即动量是否在比赛中起到了作用。
- 建议: 如果动量模型在解释比赛中的表现上表现更好,向教练提供有关如何利用动量信息的建议,以更好地准备球员应对比赛中的变化。
通过以上详细步骤,我们可以系统地建立和验证动量模型,并提供深入的分析和建议,以帮助教练更好地理解比赛中的动量效应。
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, precision_score, recall_score, confusion_matrix# 读取数据
data = pd.read_csv("2023-wimbledon-1701.csv")# 数据预处理
def preprocess_data(data):# ...(根据具体情况进行缺失值处理、特征提取等操作)return processed_data# 特征选择
def select_features(data):features = ["Momentum", "Other Features"]X = data[features]y = data["PointVictor"]return X, y# 划分训练集和测试集
def split_train_test(X, y):X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)return X_train, X_test, y_train, y_test# 建立和训练逻辑回归模型
def build_and_train_model(X_train, y_train):model = LogisticRegression()model.fit(X_train, y_train)return model# 模型预测
def make_predictions(model, X_test):y_pred = model.predict(X_test)return y_pred# 模型性能评估
def evaluate_model(y_test, y_pred):accuracy = accuracy_score(y_test, y_pred)precision = precision_score(y_test, y_pred)recall = recall_score(y_test, y_pred)conf_matrix = confusion_matrix(y_test, y_pred)return accuracy, precision, recall, conf_matrix# 可视化混淆矩阵
def plot_confusion_matrix(conf_matrix):sns.heatmap(conf_matrix, annot=True, fmt="d", cmap="Blues")plt.xlabel("Predicted Label")plt.ylabel("True Label")plt.show()# 主流程
def main():# 数据预处理processed_data = preprocess_data(data)# 特征选择X, y = select_features(processed_data)# 划分训练集和测试集X_train, X_test, y_train, y_test = split_train_test(X, y)# 建立和训练模型model = build_and_train_model(X_train, y_train)# 模型预测y_pred = make_predictions(model, X_test)#见完整版
问题三
问题三涉及开发一个模型,该模型可以预测比赛中的“momentum”变化,同时需要确定哪些因素与这种变化相关。以下是一个详细的建模思路,包括一些概念和公式:
1.定义“Momentum”:
在网球比赛中,“momentum”可以理解为某一方在比赛中的表现势头。我们可以用某种方式量化势头,例如,在每个时间点,计算某一方在过去一段时间内赢得的点的数量。
M o m e n t u m t = ∑ i = t − k t ( 1 p 1 _ w i n s _ p o i n t i − 1 p 2 _ w i n s _ p o i n t i ) Momentum_t=\sum_{i=t-k}^{t}(1_{p1\_wins\_point_i}-1_{p2\_wins\_point_i}) Momentumt=∑i=t−kt(1p1_wins_pointi−1p2_wins_pointi)
其中, M o m e n t u m t Momentum_t Momentumt是在时间点 t t t的势头, k k k是我们选择的时间窗口大小, 1 p 1 _ w i n s _ p o i n t i 1_{p1\_wins\_point_i} 1p1_wins_pointi和 1 p 2 _ w i n s _ p o i n t i 1_{p2\_wins\_point_i} 1p2_wins_pointi是指示在时间点 i i i球员1和球员2是否赢得了该点的指示函数。
2.建立预测模型:
我们可以使用机器学习模型,如线性回归、决策树或神经网络,来预测“momentum”变化。我们选择一组特征(可能包括当前比分、球员排名、比赛阶段等),并使用过去的数据进行训练。
M o m e n t u m _ C h a n g e t = f ( Features t ) Momentum\_Change_t=f(\text{Features}_t) Momentum_Changet=f(Featurest)
这里, M o m e n t u m _ C h a n g e t Momentum\_Change_t Momentum_Changet是在时间点 t t t的势头变化, Features t \text{Features}_t Featurest是我们选择的一组特征。
3.确定相关因素:
利用模型的系数或特征的重要性,可以确定哪些因素对“momentum”变化有较大影响。
Important_Features = arg max Features ∣ Coefficient/Importance ∣ \text{Important\_Features}=\arg\max_{\text{Features}}|\text{Coefficient/Importance}| Important_Features=argmaxFeatures∣Coefficient/Importance∣
4.模型评估:
使用历史比赛数据进行模型的交叉验证,并考虑评估指标,如均方误差(MeanSquaredError)或分类准确率,来评估模型的性能。
M S E = 1 n ∑ i = 1 n ( M o m e n t u m _ C h a n g e t i − M o m e n t u m _ C h a n g e ^ t i ) 2 MSE=\frac{1}{n}\sum_{i=1}^{n}(Momentum\_Change_{t_i}-\hat{Momentum\_Change}_{t_i})^2 MSE=n1∑i=1n(Momentum_Changeti−Momentum_Change^ti)2
其中, M o m e n t u m _ C h a n g e ^ t i \hat{Momentum\_Change}_{t_i} Momentum_Change^ti是模型在时间点 t i t_i ti的预测势头变化。
5.模型应用和建议:
将训练好的模型应用于新的比赛数据,以预测势头变化。如果有势头变化的迹象,可以给出建议,例如提醒球员调整策略、休息或调整心态。
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error
import matplotlib.pyplot as plt# 读取数据
data = pd.read_csv("2023-wimbledon-1701.csv")# 数据预处理
def preprocess_data(data):# ...(根据具体情况进行缺失值处理、特征提取等操作)return processed_data# 计算势头变化
def calculate_momentum_change(data, window_size=5):data["MomentumChange"] = data["PointVictor"].rolling(window=window_size).sum()return data# 特征选择
def select_features(data):features = ["Feature1", "Feature2", ...] # 根据实际数据选择特征X = data[features]y = data["MomentumChange"]return X, y# 划分训练集和测试集
def split_train_test(X, y, test_size=0.2):X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=test_size, random_state=42)return X_train, X_test, y_train, y_test# 建立和训练线性回归模型
def build_and_train_model(X_train, y_train):model = LinearRegression()model.fit(X_train, y_train)return model# 模型预测
def make_predictions(model, X_test):y_pred = model.predict(X_test)return y_pred# 模型评估
def evaluate_model(y_test, y_pred):mse = mean_squared_error(y_test, y_pred)return mse# 可视化势头变化和预测
def visualize_momentum(data, y_test, y_pred):plt.plot(data["Timestamp"], data["MomentumChange"], label="Actual Momentum Change")plt.plot(data["Timestamp"], y_pred, label="Predicted Momentum Change")plt.legend()plt.xlabel("Timestamp")plt.ylabel("Momentum Change")plt.show()# 主流程
def main():# 数据预处理processed_data = preprocess_data(data)# 计算势头变化processed_data = calculate_momentum_change(processed_data)# 特征选择X, y = select_features(processed_data)# 划分训练集和测试集X_train, X_test, y_train, y_test = split_train_test(X, y)#见完整版
问题四
1. 模型应用:
为了将我们之前构建的模型应用于新的比赛数据集,我们需要确保该数据集的特征与之前使用的数据相似。首先,加载新的比赛数据集。
new_data = pd.read_csv("new_competition_data.csv")
分析:
确保新数据集的特征与之前训练的模型兼容,可以通过比较列名、数据类型等来进行初步检查。
2. 预测势头变化:
使用问题三中训练的模型对新比赛的数据进行预测。
Momentum_Change_new = model.predict(Features_new)
分析:
观察模型对新数据集的预测效果,通过可视化或统计指标(如均方误差)来评估模型的适用性。
3. 模型评估:
计算模型在新比赛中的均方误差(MSE)等评估指标。
MSE_new = mean_squared_error(Momentum_Change_new, Momentum_Change_true)
分析:
MSE提供了模型预测误差的度量,通过与之前的训练集进行比较,评估模型在新数据上的泛化性能。
4. 因素分析:
对比赛数据的特征进行分析,了解模型在新比赛中的预测是否受到特定因素的影响。
feature_importance = pd.Series(model.coef_, index=X.columns)
分析:
通过特征重要性分析,确定哪些特征对于模型在新比赛中的预测起着关键作用,从而深入了解势头变化的影响因素。
5. 改进模型(可选):
根据因素分析的结果,考虑改进模型。
new_feature = extract_new_feature(new_data)
new_processed_data["NewFeature"] = new_feature
X_new_updated = new_processed_data[updated_features]
model_updated = build_and_train_model(X_train_updated, y_train)
分析:
通过新特征的提取和模型的重新训练,尝试提高模型在新比赛数据上的准确性,注意监测模型性能的改善。
6. 泛化性能考察:
测试模型在不同比赛、不同赛事和场地的表现。
other_competition_data = pd.read_csv("other_competition_data.csv")
分析:
通过在不同比赛数据上的表现,评估模型的泛化性能,注意观察是否存在过拟合或欠拟合的情况。
问题五
问题五:模型泛化和建议
1. 泛化性能测试:
在不同比赛、不同赛事和场地的数据上测试模型的泛化性能。
other_competition_data = pd.read_csv("other_competition_data.csv")
Features_other = other_competition_data[relevant_features]
Momentum_Change_other = model.predict(Features_other)
分析:
评估模型在其他比赛数据上的表现,关注模型是否能够泛化到不同比赛和场地。使用均方误差等指标来衡量性能。
2. 模型稳定性检验:
通过在不同时间段的比赛数据上测试模型的稳定性。
time_split_data = pd.read_csv("time_split_data.csv")
Features_time = time_split_data[relevant_features]
Momentum_Change_time = model.predict(Features_time)
分析:
考察模型对于比赛数据的时间变化是否具有稳定性。模型应该能够适应比赛风格和趋势的变化。
3. 建议球员应对事件:
基于模型的势头变化预测,为球员提供应对不同事件的建议。
event_impact = model.get_event_impact()
分析:
通过分析模型的特征重要性,了解哪些比赛事件对势头变化影响较大。为球员提供在关键时刻的应对建议,例如调整战术或情绪管理。
4. 预测比赛走势:
使用模型预测整场比赛的走势,并与实际比赛结果进行比较。
match_trend_prediction = model.predict_match_trend(Features_match)
actual_match_result = match_data["Actual_Result"]
分析:
通过比较模型预测的比赛走势和实际比赛结果,评估模型对整场比赛的预测能力。
5. 高级特征工程(可选):
尝试更复杂的特征工程,例如引入动态特征或基于事件的特征。
advanced_features = generate_advanced_features(match_data)
分析:
考虑引入更多的比赛动态信息或特殊事件的特征,以提高模型对势头变化的准确预测。
6. 模型改进和优化(可选):
根据对模型在各方面分析的结果,尝试优化模型,可能包括超参数调整、特征选择等。
optimized_model = optimize_model(X_train, y_train)
分析:
通过反复测试和调整模型,迭代优化模型的性能,确保其在各种情况下都能表现良好。
更多内容具体可以看看我的下方名片!里面包含有美赛一手资料与分析!
另外在赛中,我们也会陪大家一起解析美赛的一些方向
关注 CS数模 团队,数模不迷路~