简介本资源为2023年美国数学建模竞赛MCM/ICMC题获奖论文的完整PDF文档面向备战美赛的高校学生、数模爱好者及指导教师聚焦Wordle游戏结果数据的挖掘与趋势预测。论文系统呈现了从数据预处理、时间序列分析到ARIMA-BP神经网络融合建模、Bootstrap区间预测、多元线性回归、LSTM百分比分布预测及GMM聚类、Apriori关联规则挖掘的完整方案并包含敏感性分析、COV不确定性度量与MSE、RMSE、R²误差评估还给出了致纽约时报编辑的信件范例。资源包内仅含1个PDF文件约1.36MB便于直接阅读与打印研习。目前已有143人学习下载读者可借此掌握获奖论文的建模思路、模型融合技巧与论文写作结构是备赛阶段拆解优秀案例、提升建模与英文写作能力的实用参考。1. 从一份 25 页的获奖论文里我拆出了 Wordle 数据建模的完整链路2023 年美赛 C 题给了一份 Wordle 从 2022 年 1 月 7 日到 12 月 31 日的每日结果数据要求预测 2023 年 3 月 1 日的参与人数区间、分析单词属性对硬模式选择的影响、预测某个具体单词的猜测次数分布、评估单词难度还要挖掘数据里的隐藏规律。这份 2309397 号论文拿了 C 类奖项25 页正文里塞了 ARIMA-BP 组合预测、Bootstrap 区间估计、多元线性回归、LSTM 序列预测、GMM 聚类和 Apriori 关联规则六套模型每一套都落到了具体数字上。如果你正在准备美赛或者做时间序列加机器学习的组合项目这份论文的价值不在于它拿了什么奖而在于它把「数据预处理 → 模型选型 → 参数调优 → 误差分析 → 敏感性检验」这条链路走完整了而且每一步都有可复现的中间结果。我拆完之后的判断是它适合已经学过 ARIMA 和神经网络基础、但不知道怎么把多个模型串起来解决一个完整问题的人。2. 数据预处理与三阶段划分ARIMA-BP 组合模型的前置工程2.1 原始数据的五个异常点和处理逻辑论文拿到的数据有 12 个字段包括日期、单词、参与人数、七种猜测次数的百分比等。预处理阶段发现了 5 个异常值处理方式分两类直接删除和修正。删除的三条是单词本身有问题——marxh不存在、clen和tash不足 5 个字母这些单词对应的参与人数数据无法对应到真实游戏结果所以整行删掉。修正的两条是录入错误2569这个数字明显是22569漏了一位rprobe应该是probe多了一个字母。这里有个细节值得注意论文没有对百分比之和做归一化处理因为原始数据的百分比总和都在 98% 到 102% 之间属于四舍五入的正常误差范围强行归一化反而会引入人为偏差。用 Python 复现这个预处理逻辑核心代码如下import pandas as pd import numpy as np # 读取原始数据 df pd.read_csv(wordle_results.csv) # 删除单词字段有问题的行 invalid_words [marxh, clen, tash] df df[~df[word].isin(invalid_words)] # 修正录入错误 df.loc[df[word] rprobe, word] probe df.loc[df[reported_results] 2569, reported_results] 22569 # 检查百分比之和的分布 pct_cols [try1_pct, try2_pct, try3_pct, try4_pct, try5_pct, try6_pct, tryX_pct] df[pct_sum] df[pct_cols].sum(axis1) print(df[pct_sum].describe()) # 预期输出min 约 0.98max 约 1.02均值接近 1.00这段代码的关键参数是invalid_words列表和两个修正条件。invalid_words里的三个单词是论文明确列出的修正逻辑用loc定位后直接赋值。最后一步的pct_sum检查是为了验证论文说的「百分比之和在 98% 到 102% 之间」这个结论如果实际数据偏离这个范围说明数据版本可能不同需要重新评估是否要做归一化。2.2 三阶段划分的依据和 ARIMA-BP 的融合策略论文把参与人数变化分成三个阶段2022 年 1 月 7 日到 2 月 2 日的快速增长期增幅 348.85%峰值出现在 2 月 2 日的 361908 人2 月 3 日到 5 月 29 日的快速下降期降幅 84.29%5 月 30 日到 12 月 31 日的稳定衰减期降幅 64.14%。这个划分不是拍脑袋定的论文结合了游戏生命周期理论和玩家生命周期理论来解释第一阶段靠社交传播和每日一题的稀缺性拉新第二阶段是互联网流行病的典型衰退第三阶段剩下的是有用户粘性的核心玩家。ARIMA 和 BP 神经网络的融合方式是加权组合。ARIMA 负责提取线性趋势BP 网络负责拟合非线性残差最终预测值是两者的加权和。论文没有在正文里给出具体的权重值但从符号表里可以看到wA和wB分别代表 ARIMA 和 BP 的权重。常见做法是用最小二乘法或者网格搜索来确定这两个权重让组合模型在验证集上的 MSE 最小。from statsmodels.tsa.arima.model import ARIMA from sklearn.neural_network import MLPRegressor from sklearn.preprocessing import MinMaxScaler import numpy as np # 假设 data 是预处理后的参与人数时间序列 # 第一阶段ARIMA 拟合线性部分 arima_model ARIMA(data, order(2, 1, 2)) # 阶数需要根据 ACF/PACF 图调整 arima_fit arima_model.fit() arima_pred arima_fit.fittedvalues # 计算残差 residuals data - arima_pred # 第二阶段BP 网络拟合残差 scaler MinMaxScaler() residuals_scaled scaler.fit_transform(residuals.values.reshape(-1, 1)) bp_model MLPRegressor( hidden_layer_sizes(64, 32), # 两层隐藏层节点数根据数据量调整 activationrelu, solveradam, max_iter2000, random_state42 ) # 用滞后特征作为输入 lag 7 X np.array([residuals_scaled[i-lag:i, 0] for i in range(lag, len(residuals_scaled))]) y residuals_scaled[lag:, 0] bp_model.fit(X, y) # 组合预测 wA, wB 0.6, 0.4 # 权重可通过验证集调优 final_pred wA * arima_pred wB * bp_model.predict(X)ARIMA 的order参数需要看 ACF 和 PACF 图来定论文没有给出具体阶数但 C 题数据有明显的趋势性一般做一阶差分。BP 网络的hidden_layer_sizes设成 (64, 32) 是常见起点数据量只有 300 多条层数太深容易过拟合。lag7表示用前 7 天的残差预测下一天这个窗口大小可以调整。权重wA和wB的和为 1具体值建议用网格搜索在 0.1 到 0.9 之间以 0.05 为步长遍历选验证集 MSE 最小的组合。2.3 Bootstrap 区间预测的实现细节点预测只能给一个数但美赛题目明确要求给预测区间。论文用 Bootstrap 方法对原始数据做多次有放回重采样每次重采样都重新训练 ARIMA-BP 模型并预测 2023 年 3 月 1 日的值重复 1000 次后取预测值的 2.5% 和 97.5% 分位数得到 95% 置信区间。最终结果是 (19504.74, 20383.26)。def bootstrap_interval(data, n_bootstrap1000, alpha0.05): predictions [] n len(data) for i in range(n_bootstrap): # 有放回重采样 sample np.random.choice(data, sizen, replaceTrue) # 重新训练组合模型简化版只演示逻辑 arima_fit ARIMA(sample, order(2,1,2)).fit() pred arima_fit.forecast(steps1)[0] predictions.append(pred) lower np.percentile(predictions, 100 * alpha / 2) upper np.percentile(predictions, 100 * (1 - alpha / 2)) return lower, upper lower, upper bootstrap_interval(data.values) print(f95% 置信区间: ({lower:.2f}, {upper:.2f}))n_bootstrap设 1000 是精度和耗时的折中论文没有明确说次数但 1000 次在美赛三天时间内完全跑得完。alpha0.05对应 95% 置信水平。注意每次重采样后都要重新拟合模型不能只对预测结果做重采样否则会低估不确定性。这个过程的计算量是 1000 次 ARIMA 拟合如果数据量大可以减到 500 次分位数估计的误差在可接受范围内。3. 多元线性回归与 LSTM单词属性如何影响硬模式选择和猜测分布3.1 七个单词属性的定义和回归结果解读论文定义了 3 个定性属性和 4 个定量属性。定性属性包括首字母是元音还是辅音、是否包含重复字母、字母的常见程度。定量属性包括字母内部距离、字母频率得分等。内部距离的定义是单词中相邻字母在字母表上的距离之和比如EERIE的 E 到 E 距离 0E 到 R 距离 13R 到 I 距离 9I 到 E 距离 4总和 26。多元线性回归的目标变量是硬模式玩家比例。论文的核心发现有两个首字母从元音变成辅音时硬模式比例平均下降 0.618内部距离每增加一个单位硬模式比例平均增加 0.017。这两个系数都通过了显著性检验说明单词的拼写特征确实会影响玩家的模式选择。import statsmodels.api as sm # 构造特征矩阵 # 定性属性编码 df[first_letter_vowel] df[word].apply( lambda w: 1 if w[0] in AEIOU else 0 ) df[has_repeat] df[word].apply( lambda w: 1 if len(set(w)) len(w) else 0 ) # 定量属性内部距离 def internal_distance(word): return sum(abs(ord(word[i1]) - ord(word[i])) for i in range(len(word)-1)) df[internal_dist] df[word].apply(internal_distance) # 其他属性省略构建回归 X df[[first_letter_vowel, has_repeat, internal_dist]] X sm.add_constant(X) y df[hard_mode_pct] model sm.OLS(y, X).fit() print(model.summary()) # 关注 coef 列first_letter_vowel 应接近 -0.618 # internal_dist 应接近 0.017sm.add_constant加截距项否则回归结果会有偏差。first_letter_vowel的系数是负值表示首字母是元音时硬模式比例更高因为元音开头的单词通常更容易猜玩家更愿意挑战硬模式。internal_dist的系数是正值字母跨度越大单词越难猜硬模式比例反而上升论文的解释是硬模式玩家本身偏好挑战性。如果回归结果的系数符号和论文相反先检查特征编码方向是否一致。3.2 LSTM 预测猜测次数分布球坐标变换解决百分比约束七种猜测次数的百分比之和必须接近 100%直接让 LSTM 输出 7 个百分比值很难保证和恒为 1。论文的做法是先做球坐标变换把 7 维百分比向量映射到 6 个角度和一个半径半径固定为 1LSTM 只预测 6 个角度最后反变换回百分比。这样输出的百分比自动满足和为 1 的约束。import torch import torch.nn as nn class WordleLSTM(nn.Module): def __init__(self, input_dim8, hidden_dim64, output_dim6): super().__init__() self.lstm nn.LSTM(input_dim, hidden_dim, num_layers2, batch_firstTrue) self.fc nn.Linear(hidden_dim, output_dim) def forward(self, x): # x shape: (batch, seq_len, input_dim) lstm_out, _ self.lstm(x) # 取最后一个时间步 last_out lstm_out[:, -1, :] angles self.fc(last_out) return angles # 球坐标反变换6 个角度 - 7 个百分比 def spherical_to_pct(angles): # angles 是 6 个弧度值 pcts [] remaining 1.0 for i, a in enumerate(angles): # 用 sin 保证非负cos 控制递减 val remaining * (np.sin(a) ** 2) pcts.append(val) remaining - val pcts.append(remaining) return np.array(pcts)输入维度 8 是 7 个单词属性加参与人数输出维度 6 是球坐标的角度数。num_layers2表示两层 LSTM数据量不大时两层足够。球坐标反变换的核心是用sin(a)^2保证每个分量非负同时逐步消耗剩余比例最后一个分量直接取剩余值。这个变换的缺点是角度和百分比之间的映射不是一一对应的同一个百分比向量可能对应多组角度训练时需要用真实百分比反算角度作为标签。论文对EERIE的预测结果是 [2%, 11%, 25%, 24%, 19%, 14%, 5%]第 3 次猜测的占比最高。这个分布说明EERIE这个单词的难度中等偏上大部分玩家需要 3 到 4 次才能猜中。敏感性分析显示 COV 约为 0.4说明模型预测的不确定性中等不算特别稳定但也没有完全失控。3.3 误差分析和敏感性检验的操作要点论文用了 MSE、RMSE 和 R² 三个指标衡量预测精度。MSE 对异常值敏感RMSE 量纲和原始数据一致R² 表示模型解释了多少变异。敏感性分析做了两件事改变 LSTM 的隐藏层节点数和添加高斯噪声。隐藏层节点数从 32 到 128 遍历观察 MSE 的变化曲线噪声标准差从 0.01 到 0.1 递增看预测分布的偏移程度。from sklearn.metrics import mean_squared_error, r2_score def evaluate_model(y_true, y_pred): mse mean_squared_error(y_true, y_pred) rmse np.sqrt(mse) r2 r2_score(y_true, y_pred) return {MSE: mse, RMSE: rmse, R2: r2} # 敏感性分析噪声注入 noise_levels [0.01, 0.03, 0.05, 0.08, 0.1] results [] for nl in noise_levels: noisy_input X_test np.random.normal(0, nl, X_test.shape) pred model.predict(noisy_input) results.append(evaluate_model(y_test, pred))噪声注入时要注意只加在测试集输入上不能污染训练集。noise_levels的选择依据是数据本身的量级如果输入特征已经归一化到 [0,1]0.01 到 0.1 的噪声是合理的。如果 MSE 随噪声增加急剧上升说明模型对输入扰动敏感泛化能力存疑。论文的 COV 计算方式是预测标准差除以预测均值0.4 意味着预测值的波动幅度是均值的 40%在时间序列预测里属于中等不确定性。4. GMM 聚类与 Apriori 关联规则单词难度分级和字母组合挖掘4.1 六个难度指标和 GMM 聚类流程论文提取了 6 个指标衡量单词难度RDC重复字母数量、TE字母熵、SK跳跃度、NFC首字母常见度、NON字母常见度、HL单词长度但 Wordle 固定 5 字母所以这个指标实际是常数。用这 6 个指标做 GMM 聚类把单词分成 5 个难度等级。EERIE被分到第 III 级属于中等难度。GMM 和 K-Means 的区别在于 GMM 给出的是概率归属每个单词属于某个簇的概率而不是硬分类。论文没有说用了多少个高斯分量但从 5 个难度等级反推n_components5。from sklearn.mixture import GaussianMixture from sklearn.preprocessing import StandardScaler # 构造 6 个难度指标 features df[[RDC, TE, SK, NFC, NON, HL]].values # 标准化 scaler StandardScaler() features_scaled scaler.fit_transform(features) # GMM 聚类 gmm GaussianMixture( n_components5, covariance_typefull, # 每个簇有自己的协方差矩阵 random_state42, max_iter200 ) gmm.fit(features_scaled) labels gmm.predict(features_scaled) # 查看 EERIE 的难度等级 eerie_idx df[df[word] EERIE].index[0] print(fEERIE 难度等级: {labels[eerie_idx]})covariance_typefull允许每个簇有不同形状的协方差矩阵比spherical更灵活但参数更多。数据量只有 300 多条full类型可能导致过拟合可以试tied或diag做对比。max_iter200是 EM 算法的最大迭代次数通常 100 到 300 之间足够收敛。聚类结果需要做稳定性检验换random_state跑多次看EERIE的标签是否稳定在同一个等级。4.2 Apriori 关联规则挖掘字母共现模式论文用 Apriori 算法挖掘 Wordle 单词中的字母组合规律发现 A、S、E 和 F、T、L 经常一起出现。这个结论对猜词策略有直接指导意义优先猜包含这些字母组合的单词能更快缩小候选范围。from mlxtend.frequent_patterns import apriori, association_rules from mlxtend.preprocessing import TransactionEncoder # 把每个单词拆成字母集合 transactions [list(set(word)) for word in df[word].tolist()] te TransactionEncoder() te_array te.fit(transactions).transform(transactions) df_te pd.DataFrame(te_array, columnste.columns_) # 频繁项集 frequent_itemsets apriori( df_te, min_support0.1, # 至少 10% 的单词包含该字母组合 use_colnamesTrue ) # 关联规则 rules association_rules( frequent_itemsets, metriclift, min_threshold1.2 # 提升度大于 1.2 才算有意义的关联 ) print(rules[[antecedents, consequents, support, lift]].head(10))min_support0.1表示字母组合至少在 10% 的单词中出现这个阈值可以调低到 0.05 挖掘更稀疏的模式。min_threshold1.2是提升度阈值大于 1 表示正相关1.2 以上才算有实际意义的强关联。Apriori 的输出里antecedents和consequents是 frozenset 类型需要转换成列表才能方便阅读。论文提到的 A-S-E 和 F-T-L 组合在规则表里应该能找到对应的项集。5. 避坑与排查复现这份论文时最容易翻车的五个地方5.1 现象ARIMA 拟合报错「数据非平稳」原因原始参与人数序列有明显趋势不满足 ARIMA 的平稳性假设。论文在正文里没有详细写差分阶数但 C 题数据做一阶差分后 ADF 检验 p 值才能小于 0.05。解决先做 ADF 检验如果 p 值大于 0.05 就做一阶差分还不行就做二阶。差分后的序列长度减 1预测时记得把差分还原回去。from statsmodels.tsa.stattools import adfuller result adfuller(data) print(fADF 统计量: {result[0]}, p 值: {result[1]}) if result[1] 0.05: data_diff data.diff().dropna() result_diff adfuller(data_diff) print(f差分后 p 值: {result_diff[1]})5.2 现象LSTM 输出的百分比之和偏离 100%原因球坐标反变换的实现有误或者角度预测值超出了合理范围。sin(a)^2在 a 取任意实数时都在 [0,1] 之间但多个分量相加可能超过 1。解决在反变换后做一次归一化或者改用 softmax 作为输出层的激活函数。softmax 天然保证输出和为 1但会压缩极端值需要根据数据分布选择。5.3 现象GMM 聚类每次运行结果不一样原因GMM 的 EM 算法对初始值敏感random_state不同会导致收敛到不同的局部最优。解决设置固定的random_state并且用n_init参数多次初始化取最优。n_init10表示跑 10 次取对数似然最大的那次。gmm GaussianMixture( n_components5, n_init10, # 多次初始化 random_state42 )5.4 现象Bootstrap 区间预测耗时过长原因1000 次重采样每次都要重新拟合 ARIMA单次拟合 0.5 秒的话总共要 8 分钟以上。解决用joblib并行化或者减少重采样次数到 500 次。也可以先用 ARIMA 拟合一次然后只对残差做 Bootstrap最后把残差的分位数加回点预测值。5.5 现象Apriori 挖掘出的规则太多无法解释原因min_support设得太低产生了大量低频字母组合。解决先把min_support从 0.1 开始试如果规则超过 50 条就提高到 0.15 或 0.2。同时用lift排序只看提升度最高的前 20 条。字母级别的关联规则本身解释性就弱可以改成挖掘「单词模式」而不是「字母组合」比如把单词按首字母和长度分组后再做关联分析。6. 从论文到可复现项目把六套模型串成一条流水线的具体技巧这份论文最大的价值不是单个模型的精度而是它展示了一条完整的建模流水线先用 ARIMA-BP 做时间序列预测再用 Bootstrap 给区间然后用回归分析找影响因素接着用 LSTM 做分布预测最后用 GMM 和 Apriori 做无监督挖掘。如果你要复现或者在此基础上改进我建议按下面的顺序搭代码结构。先建一个data_preprocessing.py把异常值处理和特征工程封装成函数。特征工程里最关键的是七个单词属性的计算尤其是内部距离和字母熵这两个特征在回归和 LSTM 里都用到。字母熵的计算公式是-sum(p * log(p))p 是每个字母在单词中出现的频率。def letter_entropy(word): from collections import Counter import math counts Counter(word) total len(word) entropy 0 for count in counts.values(): p count / total entropy - p * math.log(p) return entropy df[TE] df[word].apply(letter_entropy)然后建models/目录每个模型一个文件。ARIMA-BP 组合模型里权重调优用网格搜索把wA从 0.1 到 0.9 遍历每次计算验证集 MSE选最小的。LSTM 的训练用早停法验证集 loss 连续 10 个 epoch 不下降就停防止过拟合。GMM 的n_components用 BIC 准则选从 2 到 8 遍历BIC 最小的就是最优簇数。from sklearn.mixture import GaussianMixture bic_scores [] for n in range(2, 9): gmm GaussianMixture(n_componentsn, n_init10, random_state42) gmm.fit(features_scaled) bic_scores.append(gmm.bic(features_scaled)) optimal_n np.argmin(bic_scores) 2 print(fBIC 最优簇数: {optimal_n})最后建一个pipeline.py把所有步骤串起来从原始 CSV 到最终预测结果一键跑通。跑完之后重点检查三个地方ARIMA 残差的白噪声检验Ljung-Box 检验 p 值大于 0.05、LSTM 预测分布的 KL 散度和真实分布对比、GMM 聚类的轮廓系数大于 0.3 算合理。这三个指标任何一个不达标就回到对应的模块调参。我自己的习惯是每次跑完流水线先把中间结果存成 CSV包括预处理后的数据、ARIMA 点预测、Bootstrap 区间、回归系数、LSTM 角度输出、GMM 标签和 Apriori 规则表。这样出问题的时候可以逐段排查不用从头跑。论文里EERIE的预测分布 [2%, 11%, 25%, 24%, 19%, 14%, 5%] 可以作为一个基准如果你的 LSTM 输出和这个差太远先检查球坐标变换的实现是否正确再检查输入特征的归一化方式是否和论文一致。从那以后我每次复现论文都强制走一遍「中间结果落盘 → 逐段验证 → 基准对比」的流程能省掉大量调试时间。希望帮到你。本文还有配套的精品资源点击获取
