美赛C题Wordle预测:时间序列特征工程与可解释建模避坑指南

发布时间:2026/10/27 23:42:52
美赛C题Wordle预测:时间序列特征工程与可解释建模避坑指南 简介这份资源汇集了2023年美国大学生数学建模竞赛C题的完整备赛材料面向准备参加美赛或各类数学建模竞赛的学生与指导教师。包内包含赛题分析、数据处理、模型构建与论文写作等多维度的参考内容尤其适合需要快速了解C题建模思路、学习数据清洗与回归聚类方法以及规范论文排版的读者。资源共208个文件涵盖pdf论文与参考文献、xlsx数据表、docx建模笔记、png图表、txt代码说明、sav与csv统计文件等压缩包总大小约59.42MB类型丰富便于按需查阅与二次学习。目前已有176人在线学习具有一定的参考价值。透过这些资料可系统梳理从数据预处理如滑动窗口平滑、单词难度计算到聚类分析K-Means、回归拟合及模型验证的完整流程还能借鉴第三问模型、公式推导及Word文档写作的具体实现方式为独立完成同类赛题提供有力支撑。1. 2023年美国大学生数学建模竞赛C题它到底在考什么熬夜建模前先想清楚2023年美国大学生数学建模竞赛C题给的不是复杂物理方程也不是海量传感器数据而是一张按天记录的Wordle游戏结果表。你要预测未来每天有多少人玩、多少人用Hard模式还要解释为什么人数会波动。很多队拿到题就冲上去套时间序列模型结果三天三夜全耗在调参上最后评委一问“为什么选这个模型”就卡壳。这道题真正考的是两件事把人类行为拆成可解释的特征以及用对验证方式。适合想打美赛拿奖的本科生也适合刚接触时序预测、想知道“预测人的行为”和“预测机器指标”差在哪的从业者。2. 从赛题数据到第一份洞察C题给的数据里哪几个字段才是真正的信号2.1 原始数据长什么样先别建模先做三次拆分2023年C题的数据是Wordle在某个时间段内按天汇总的统计表。常见字段至少包括日期、局数编号、当日词汇、当日报告人数、Hard模式报告人数以及结果分布类字段。以赛题实际提供的版本为准但多数队伍都会按下面这套思路整理。字段类型价值判断Date日期时间序列的索引必须转成datetimeContest Number整数单调递增适合做生命周期趋势项Word文本可以挖难度特征但通常不是主要变量Number of Reports整数主预测目标之一Number in Hard Mode整数主预测目标之二常以占比形式使用拿到表的第一件事不是画折线图而是做三次拆分。第一把日期拆到星期维度看周内规律。Wordle是很多人通勤或摸鱼时玩的周一和周五的人气往往明显不一样。第二把局数编号拆成趋势项看游戏生命周期。Wordle在数据覆盖期内整体热度是往下走的但中间可能因为新闻事件出现尖峰。第三把“骤升点”单独拉出来和新闻事件对照。这个动作的价值会在写论文的建模动机部分体现出来。import pandas as pd df pd.read_csv(wordle_results.csv, parse_dates[Date]) df[dow] df[Date].dt.dayofweek # 周一0周日6 df[trend] df[Contest Number] # 局数编号作为趋势 df[weekend] (df[dow] 5).astype(int) # 周末标记 print(df.groupby(dow)[Number of Reports].mean())这段代码做完你会看到星期哑变量的均值差。如果周内差异超过百分之十就说明星期效应不能忽略。trend列不要直接塞进模型后就完事它的分布形状决定了你要用线性还是对数趋势。2.2 预测目标不是“人数”而是“百分比误差”先搞懂评价函数再决定策略这道题的评价指标不是RMSE而是平均绝对百分比误差MAPE。MAPE的计算方式是对每一天计算真实值与预测值之差的绝对值除以真实值再求平均、乘100%。这意味着同样相差100人在玩家数3000的天里误差是3%在玩家数300的天里误差是33%。所以模型必须优先保住“低人气日”的预测精度而低人气日恰好容易出现在周末和节假日。能不能用RMSE代替MAPE做训练可以但分数不会太好。RMSE对大误差敏感会把力气花在修正几个尖峰日上MAPE则惩罚的是“相对偏差”更贴合赛题。因此常见做法是以log1p之后的目标做回归让模型在指数尺度上缩小相对误差再把预测结果做expm1还原。还有一个很实在的坑如果真实值本身接近零MAPE会瞬间变大所以预测值必须被限制在一个正数下限以上。import numpy as np from sklearn.metrics import mean_absolute_percentage_error y_true np.array([12000, 8000, 3500, 900]) y_pred np.array([11000, 8200, 3000, 700]) print(mean_absolute_percentage_error(y_true, y_pred)) def mape_clip(y_true, y_pred, floor100): y_pred np.maximum(y_pred, floor) return np.mean(np.abs(y_true - y_pred) / y_true) * 100这里对预测值加了一个下限避免把很冷清的一天预测成接近零。floor100是一个经验值你可以按数据量级调整。用这个函数做最终评估比直接调用库函数更能反映赛题场景。2.3 两个必须处理的数据缺口缺失的日期和零报告Wordle官方数据偶尔会出现某一天没有记录的情况。直接删掉会让时间序列不连续滞后特征错位。零报告比缺失更隐蔽不是没人玩而是当天数据没入库。如果放任不管模型会学到“某天突然归零”导致滞后特征全部被污染。处理时先区分“真零”和“假零”。真零在数据里几乎不存在因为Wordle这种全民级游戏不会真的没人玩。遇到疑似零值先看前后几天。前后都是正常量级中间一个零那八成是缺数。常见补法是用前一天和后一天的平均值或者直接做线性插值。做插值要放在构造滞后特征之前否则shift出来的窗口里全是脏数据。这个顺序性很强见过有队伍先造特征再清洗结果回填值被当成真实波动模型直接翻车。3. 先跑通一个能拿分的基线方案线性回归把星期效应和生命周期放进同一张表3.1 为什么不直接上Prophet、LSTM或XGBoost美赛C题不是Kaggle排位赛评委看的是“你有没有想清楚为什么这样做”。Prophet能跑但它的趋势、节假日和季节项对评委来说是个黑匣子。LSTM更是吃力不讨好几百行数据训练深度模型方差大、可解释性差。XGBoost能拟合得很漂亮但特征重要性一出来评委追问“为什么这个特征排第一”时很难答。线性回归加手工特征的组合是这道题性价比最高的开局每个特征你都能解释来源每个系数都能转成一句业务结论。最朴素的一组特征就能拿到一个能看的基线星期几哑变量、局数编号、滞后7天的平均报告人数。这三样分别对应人类行为中的周规律、生命周期、惯性。别贪多先让这组特征跑通全流程。3.2 最小特征集代码构建特征、拟合、评价import pandas as pd import numpy as np import statsmodels.api as sm df[log_reports] np.log1p(df[Number of Reports]) # 滞后7天均值只使用过去信息不做未来泄漏 df[last7] ( df[Number of Reports] .shift(1) .rolling(7, min_periods1) .mean() ) # 星期哑变量 dow_dummies pd.get_dummies(df[dow], prefixdow, drop_firstTrue).astype(int) X pd.concat([ dow_dummies, df[[trend, last7]].reset_index(dropTrue) ], axis1) y df[log_reports] # 去掉头部有NaN的行 mask X.notna().all(axis1) y.notna() X, y X[mask], y[mask] X sm.add_constant(X) model sm.OLS(y, X).fit() print(model.summary())shift(1)是为了使用“前一天”的信息rolling(7, min_periods1)计算的是过去7天的均值min_periods1保证早期数据也有值。关键点是mask过滤掉建立窗口时留下的空值不然sm.OLS会直接报错。输出里的系数解释是trend系数为负说明游戏热度随局数增加在衰减last7系数接近1说明玩法有强烈惯性某个星期哑变量为负说明那天人气低于基准日。3.3 参数怎么设趋势用“对数”而不是一根直线很多队伍把局数编号直接当线性特征扔进模型结果预测到后期变成负数人群完全不可信。热度的衰减不会是一条直线到底更像是对数衰减。用trend_log np.log(contest_number)替代trend是最简单的修正。另外可以考虑在新闻事件前后加一个分段转折点事件后的日期标1事件前标0这样模型能学到一个结构性变化。df[trend_log] np.log(df[trend]) df[post_news] (df[Date] 2022-02-01).astype(int)日期节点要根据你使用的数据版本去选这里只是一个示例。判断转折点的方法很简单画一下序列图找到斜率突变的日期再结合公开新闻事件做对照。如果你选了多个事件节点记得检查系数显著性和VIF避免互相打架。4. 从基线到能讲故事的模型滞后特征、滚动验证和可解释性三板斧4.1 加滞后特征像走钢丝什么时候该加什么时候就是数据泄漏基线里的last7属于滞后特征的一种。它有用因为用户行为有惯性它有风险因为未来预测时要递归生成。训练时你可以用前一天的真实值构造lag1测试时拿不到这个真实值只能用前一天的预测值回填。如果不管这一点验证集上很好看实际提交后分数崩得很难看。def rolling_forecast(model, X_hist, n_days7, lag_collag1): history X_hist[lag_col].copy() preds [] for i in range(n_days): X_new X_hist.iloc[[-1]].copy() X_new[lag_col] history.iloc[-1] pred model.predict(X_new)[0] preds.append(pred) history pd.concat([history, pd.Series([pred])]) return preds这个函数展示了迭代预测的核心逻辑每一轮都把上一轮的预测值当作最新历史喂给滞后特征。它是简化版实际使用时要先冻结外部特征星期几、趋势只让滞后部分递归。如果外部特征里有移动平均同样要存一个历史序列逐日更新否则误差会被自己喂大的后悔药害惨。4.2 用TimeSeriesSplit替代随机K折序列数据不能洗牌随机K折在普通回归里没问题在时间序列里就是泄漏。昨天和今天是强相关的把今天放进训练集、明天放进测试集模型等于提前知道了答案。常见做法是TimeSeriesSplit训练集永远在前测试集永远在后。下面这段代码中gap7是我强烈建议加的如果特征里用了滞后7天测试集第一天会用到训练集最后7天的真实值不设gap就等于间接偷看。from sklearn.model_selection import TimeSeriesSplit tscv TimeSeriesSplit(n_splits5, test_size7, gap7) for train_idx, val_idx in tscv.split(X): X_train, X_val X.iloc[train_idx], X.iloc[val_idx] y_train, y_val y.iloc[train_idx], y.iloc[val_idx] # 在每个fold上重新拟合模型并记录MAPEtest_size7对应一周的预测窗口gap7对应滞后窗口的边界。不要在小样本上把n_splits设太大否则每个训练集只有几十行模型波动会很大。建议至少保证每个训练fold有70天以上数据。4.3 可解释性输出把系数换算成“周末人气降了百分之几”这种人话线性回归的好处是系数可以直接翻译。假设以周一为基准周日的系数是-0.18这句话应该写成“周日比周一低约16%”换算方式是np.exp(-0.18) - 1 ≈ -0.165。如果用了log目标所有解释都要先过指数函数不能直接拿系数说“低了0.18”。这种细节在论文里特别加分评委一看就知道你真的懂模型。Hard模式占比也可以用同样的方式单独建模。占比是0到1之间的连续变量直接线性回归可能出现负数。一个常见做法是做logit变换log(p/(1-p))预测完再还原。如果还原后某个样本超出[0,1]就截断到边界。这个模型的系数解释更绕但结论更清晰Hard模式占比整体平稳说明核心玩家群体的复购率很高。5. C题翻车避坑手册从数据泄漏到报告重心五个高频踩坑记录5.1 随机打乱数据做交叉验证验证集分数好看上分就崩现象用train_test_split默认方式随机切分MAPE低得感人提交后完全对不上。 原因相邻日期的样本高度相关模型记住了昨天而不是学会了规律。 解决所有验证一律用TimeSeriesSplit并在构造滞后特征后保留至少7天的gap。5.2 用“昨天人数”做特征预测未来7天时拿不到特征值现象训练集和验证集都在同一条时间轴上回测分数不错换成真正的未来7天代码直接报错或者预测值千篇一律。 原因lag1在预测未来时没有真实值可用而模型已经把这一列当成最强信号。 解决写一个迭代滚动预测函数把前一天的预测值当作今天的lag1。不要偷懒也不要用“和训练集最后一天的真实值”复制粘贴凑数。5.3 追精度追到黑匣子模型评委一问就卡壳现象某队用XGBoost把验证MAPE压到很低答辩时被问“为什么这个特征重要”只能答“特征是模型自动挑的”。 原因树模型的特征重要性不能直接等价于业务归因评委不接受黑匣子解释。 解决即使要用XGBoost也要同时跑一个线性参照系把两条路线的趋势方向、星期效应做对照。论文主线讲线性回归复杂模型放附录当稳健性检验。5.4 对Hard模式占比用普通线性回归预测出负数现象Hard模式占比预测结果里有-0.05这种值截断后又出现一堆0和1边界值。 原因线性回归假设目标服从正态分布占比变量被强行拉了回来尾部超界。 解决改用logit回归预测前对0.999和0.001做clip避免log里出现0或1。提交前把边界影响写进附录。5.5 论文全在堆公式没有把预测偏差还原成业务故事现象评委看完摘要不知道这题到底研究了什么。 原因全文只写了“我们用了ARIMA”没有回答“为什么人会少”“是衰减还是事件冲击”。 解决每一章开头先给结论例如“周日比周一少15%”“新闻事件带来42%的临时尖峰”。图是辅助文字里必须有一句明确判断。6. 收尾用“预测加复盘”把模型写进论文并验证它真能用于未来一周做完模型不验证等于白做。我的习惯是留出最后14天不训练在滚动窗口上每天预测一次和真实值画在一起。不是只看一个总体MAPE而是看误差集中在星期几、是不是某次新闻事件导致整体偏移。这样写进论文既可以当“模型有效性验证”也可以顺带展示模型的失败边界。复盘时还有一个容易忽略的步骤把“预测差的那几天”单独拎出来看看当天Wordle单词是不是特别生僻或特别简单。生僻词会让报告基数下降但Hard模式玩家占比可能会上升。如果你想在论文里加一点点深度把这组对照做出来放一个表就行。这不是赛题要求里必须有的东西但它会让你的模型显得更像“理解人的行为”而不是在拟合数字。另外最终提交的论文里要有敏感性分析一页。我一般会做三个版本基础线性回归、加滞后特征、加新闻事件哑变量。表格列出滚动验证MAPE三行数据就能说明每个特征模块贡献了多少。评委看到这种对比比你写一整页原理更信服。最后说个教训有队伍把全部精力花在把MAPE从18%压到17%结果没有时间写清楚建模假设和验证流程最后奖项平平。这个比赛评的不是最低误差而是“讲一个完整可信的故事”。先保证模型每一处选择都有理由再去优化后面小数点。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询