复试准备到DAY4我把手边的回归项目实战定成了“预测新冠人数”。这个题目在一众电商销量、房价预测的复试题里不算新但确实非常典型它是一个连续的时序回归问题能串起特征工程、模型选型、评估指标和数据泄漏这些复试高频考点的几乎全部内容。这套DAY4项目的复盘我整理成一份能直接照着做的实操笔记有我的踩坑过程也有最后复盘时觉得值得写进复试回答的思路。如果你也在准备机器学习方向的复试或者刚好想拿时序回归练手这篇应该能帮你少走不少弯路。1. 复试清单里为什么会冒出回归预测这个项目1.1 “预测新冠人数”到底是一个什么问题先把题目翻译成机器学习的话给定过去若干天的每日新增确诊人数要求预测未来某几天的新增人数。这里的目标变量是连续型数值所以是一个回归问题又因为数据是沿着时间顺序采集的所以它同时也是一个时序预测问题。这两个定语决定了后面所有操作的走向。普通的回归任务数据之间假设是独立同分布的随机打乱数据做交叉验证通常问题不大。但时序回归不行第T天的数值天然依赖于第T-1天、第T-2天的结果一旦把时间顺序打乱就是在人为制造数据泄漏得到的验证分数没有任何参考意义。这个点我在复习初期根本没意识到直到把随机K折跑出来的完美分数画成图才发现模型已经把“未来信息”偷着用了。这部分后面第3章我会专门展开。另外这个题目还可以拆成两种预测方式一是单步预测即只用历史数据预测明天一天二是多步预测即预测未来7天或者14天。复试项目里我更推荐先做多步中的“滚动预测”思路更清晰也更接近现实场景。简单说就是每预测完一天把预测值拼回历史序列再接着预测下一天。这样虽然误差会逐日累积但反而能体现你对预测不确定性的理解面试时可以大大方方讲出来。1.2 项目目标拆解从题目到可量化任务我拿到这个题目后第一件事不是急着找数据而是把目标拆成几条能落地的任务构造一个监督学习数据集每一行是一个样本特征是当天的各项历史信息过去7天、14天的新增数、星期几、月份等标签是当天实际新增数。采用时间序列切分最后14天完全留出不做训练只做验证模拟“我站在今天预测未来”的真实场景。模型选型至少对比线性回归、正则化线性模型、随机森林、梯度提升树这四类给出选择理由和结果对比。评估指标同时看RMSE、MAE、MAPE并解释为什么在疫情类数据里相对误差指标要谨慎使用。这套拆解出来之后项目的骨架就清楚了。数据我用的是一个模拟构造的每日新增统计序列字段只有date、daily_new_cases、daily_new_deaths这三列。为什么不强调真实数据集因为复试场景下数据来源不重要重要的是你如何处理它。我完全可以大大方方告诉面试官“我在一份公开统计风格的数据上完成了建模流程”然后讲清楚流程本身这反而更安全也更聚焦。1.3 数据可用性与合规边界用什么数据、如何构造训练集关于数据获取我建议复试项目不要纠结于能不能找到特别权威的数据源。网上各种每日新增统计很多字段基本都差不多拿其中一段连续历史记录就足够。真正重要的是你在项目文档里写清楚三件事数据覆盖的时间范围、字段定义、以及为什么要截取这段区间。比如我最终采用的是某个平台整理的历史每日新增数跨度大约一年中间有几个明显的异常抬升点。我对原始数据做了两步处理第一步只保留“每日新增感染人数”这一列作为核心变量另外保留“每日新增治愈人数”作为可选的辅助特征第二步手动构造一个连续日期索引从第0天一直递增这个特征后面会用来捕捉长期趋势。构造训练集时有一个很关键的习惯先做日期对齐再做特征拼接。所有特征都必须以“某一天的信息”为粒度不能把整段序列的统计值直接当特征加进去。比如“这14天的新增数均值”它必须是在某个窗口内算出来的窗口滑到哪一天那一行特征就对应该天。如果先对整个序列算一个全局均值再复制到每一行这个特征就是废的还会给模型带去误导。这个坑我踩过后面详细说。2. 数据预处理和特征工程的一条龙操作2.1 拿到每日序列后先要处理的脏数据时序数据的脏和周表数据的脏很不一样。表格数据里某一行缺失可以删掉时序数据里某一天缺失删掉之后日期就断了后面所有lag计算全部会错位。所以时序缺失的第一原则是能补就不要删。我当时拿到序列发现中间缺了三天后面还跟着一个明显异常的大数值。我的处理方式是分三步走用前向填充用前一天的值补上先保证序列连续避免后续滑窗断裂再用线性插值对比一下前向填充的结果如果两者差距不大就说明那几天没有结构性突变选用更稳妥的前向填充异常大数值先不急着删单独拉出来看前后几天。如果它符合某种节假日效应导致的抬升就保留并在特征里加一个“是否为节假日/重大事件日”的脉冲标记如果是明显的录入错误才允许剔除。这里有个容易被忽视的细节缺失值要不要补、用什么补本身会影响后面所有滞后特征和滚动特征。我一开始图省事直接用了全局均值去补缺失天结果那几天的预测曲线塌成一条水平段因为模型学到的“正常值”变成了整个序列的平均水平。换成前向填充和线性插值之后曲线才恢复连贯性。2.2 日期类特征星期、月份、节假日与趋势项日期本身不是数值但可以拆出一堆有效的特征。我按重要性排了个序星期几weekday很多统计序列都有星期效应工作日、周末的数值波动规律不一样模型能靠这个特征学到周期性。是否节假日is_holiday节假日前后往往会出现数值突增或骤减用一个0/1标记可以让模型在识别异常抬升时不用额外消耗树模型的深度。月度编号month如果有跨度半年以上的数据月份可以捕捉季节性波动。天数序号days_since_start从序列第一天开始递增的整数作为全局趋势项。这个特征对线性回归特别重要它相当于直接给模型一根“时间轴”否则线性模型只能靠截距预测一个常数。还有一个容易漏掉的特征是“一阶差分”当天的值减去前一天的值它表达的是短期的变化速度。把差分作为特征放进模型相当于告诉模型“昨天涨了还是跌了”比单纯给原始值更有效。我自己做的时候把差分值、差分后7日均值都放进特征表里树模型的效果立马上了一个台阶。2.3 滑窗与滞后特征lag特征、滚动均值与波动率这一块是整个特征工程的核心。时序预测最朴素的思路就是历史重复自己。为了把“历史重复”变成模型能读的数字我构造了三组特征第一组是滞后特征lag。分别取前1天、前2天、前3天、前7天、前14天的新增数作为特征。为什么要这样取而不是连续取30天因为数据里存在明显的7天周期滞后7天的值比滞后5天更有解释力而滞后1到3天捕捉的是极短期的惯性。第二组是滚动统计特征。计算过去7天和14天的滚动均值、滚动标准差、滚动最大值。滚动均值能平滑短期噪声滚动标准差反映波动程度。这里要特别小心一点所有滚动窗口的起点和终点都必须严格小于当前预测日。比如要预测第T天只能用第T-1天及之前的数据算滚动均值一旦手滑把第T天自己也算进去了这就是标准的泄漏。第三组是比率特征。比如“过去3天均值 / 过去14天均值”表达短期相对中长期的水平。这类特征在树模型里经常能挖出更深层的模式而且它天然做了归一化不受整体数值量级影响。2.4 特征缩放与目标变换为什么常用对数变换很多入门教程说到特征缩放就一句“用StandardScaler”但在时序回归里特征缩放有两层用意。第一层很常规线性模型和带L2正则的模型对特征尺度敏感把所有数值型特征缩放到均值为0、标准差为1能让模型收敛更快。第二层是很多人忽略的目标变量本身的分布。如果每日新增数在不同阶段量级差距很大比如早期可能是几百后期变成几万那么直接做回归时模型的误差会被量级大的样本主导。这时候我习惯对目标变量做对数变换也就是把 y 换成 log(y1)。加1是为了防止0取对数无意义。这样处理后模型预测的是对数量级回算时要再做指数变换。我实测下来对数变换对这类有指数增长趋势的数据非常有效它把乘法关系变成近似加法关系线性模型也能拟合出不错的趋势。当然对数变换不是银弹。如果数据里本身就有很多0值或者你更关心预测值的绝对量而非相对量那么要慎重。我当时的做法是同时训练两个版本——一个用原始值回归一个用对数变换回归最后在验证集上比较MAE和MAPE选择更优的作为主模型。3. 从线性回归到梯度提升模型选型的真实对比3.1 先跑线性回归不是凑数是找基线很多人一上来就上XGBoost我反而不建议在复试项目里这么做。模型不是越复杂越好而是要能回答“你为什么选它”。最稳的做法是从线性回归开始。线性回归在这个项目里绝不是摆设。只要把趋势项days_since_start和周期项weekday放进特征线性回归已经能拟合出一个带上升趋势和星期波动的预测曲线。它的优势是透明、可解释能看到每个特征的系数大小方便你在面试时解释“这个特征系数是正的意味着随着时间推移预测值总体上升”。缺点是它对非线性交互和突变点不敏感预测曲线容易偏“直”。我在项目里把线性回归当作baseline记下它的验证集MAE后面所有模型都跟它比。如果没有baseline后面模型调得好坏就失去参照物。3.2 正则化线性模型Ridge和Lasso的取舍线性回归之后下一步我会加Ridge和Lasso。这两个模型解决的是同一个问题特征多了之后简单的线性回归容易过拟合尤其是滞后特征之间存在很强的共线性时系数会变得不稳定。Ridge是把所有特征系数的平方和加入损失函数让系数整体收缩但不归零Lasso则是对系数绝对值之和做惩罚可以把不重要的特征系数直接压缩到0相当于在做一个嵌入式特征选择。我那时特征有二十多个用了Lasso之后真正被保留下来的特征只有十来个星期几、短期滞后、滚动均值都在而一些噪声比较大的高阶交互特征被自动筛掉了。这个结果很适合写进复试回答因为你能从特征选择的角度解释正则化背后的意义而不是光背公式。3.3 树模型与梯度提升随机森林、XGBoost/LightGBM树模型在处理这种带周期、滞后、非线性突变的特征表时效果通常比线性模型高一截。我试了随机森林和LightGBM两种简单说下体会随机森林训练快不容易过拟合对特征尺度不敏感。缺点是外推能力弱如果测试期的数值比训练期整体高很多它会倾向于预测到训练集见过的上限在强趋势数据上容易吃亏。梯度提升树LightGBM拟合能力强能捕捉线性模型学不到的交互效应但对参数相对敏感需要调学习率、树的深度、叶子节点数等。它的一个重要优势是能做特征重要性排序方便我们看到“过去7天滚动均值”这类特征贡献有多大。我不会一上来就追求把LightGBM调到极致而是先用默认参数跑通流程记录结果再微调两三组参数。复试回答里讲清楚“我用默认参数跑出baseline然后调了learning_rate和num_leaves验证集MAPE下降了十个百分点”这种话比“我用了某个模型效果好”要有说服力得多。3.4 时序场景下的数据划分陷阱随机K折会漏信息这是全项目里我认为最重要、也最容易被问倒的一节。普通回归任务用train_test_split随机划分没问题。但时序预测一旦随机划分就会发生这样的荒唐事训练集里包含第100天的数据验证集里包含第99天的数据模型在训练时已经看过第100天的走势然后要去“预测”第99天分数当然漂亮但没有任何意义。正确做法有两种我推荐都用上一是留出法把时间轴上最后一段比如最后14天完整留出来当验证集训练只用这之前的全部数据。 二是时序交叉验证用sklearn的TimeSeriesSplit或自定义一个expanding window。比如第一次用前30天训练、接下来7天验证第二次用前37天训练、再后面7天验证窗口不断扩展。这样既能充分利用数据又不会出现未来信息泄漏。我当时分别做了这两种验证发现结果差距非常明显随机K折的MAE比时序切分低了百分之三十但那是假象时序切分下的分数虽然没那么好看却和最后盲测的感觉更一致。这个对比本身就是很好的复试素材。3.5 评估指标怎么选RMSE、MAE、MAPE各自适用场景评估这一步我同时算了三个指标但解释的时候各有侧重RMSE均方根误差对大误差非常敏感。如果某一天预测差得离谱RMSE会剧烈上升。它适合用来发现模型的“极端失误”。MAE平均绝对误差更稳健能反映平均的绝对偏差。但它是一个绝对量要看真实值的量级才有意义。MAPE平均绝对百分比误差把误差除以真实值得到百分比直观好用。但真实值很小时会爆表。比如某天真实值只有5预测值是25误差百分比就是400%会拉高整体MAPE。所以数据里有大量接近0的取值时我会标注说MAPE只作为参考不以它为主指标。我在项目最终的表格里把三个指标都列出来再附一句“以MAE和MAPE为主RMSE作为稳健性参考”。这种细节问题面试官很容易追问提前准备准没错。4. 实战过程中踩过的坑与排查链路4.1 坑一滞后特征不小心把未来的数放进训练集第一个坑是构造lag特征时对齐错位。我的目标是把第T天的数据作为标签那么第T天的特征只能来自第T-1天及之前。结果我在写代码时图省事直接用pandas的shift(0)去取“当天值当作滞后一天的特征”等于特征里包含了当天的真实值。训练时每一行都自带标准答案RMSE直接逼近0。排查链路是这样的我发现训练集R2高达0.999第一反应不是开心而是慌因为验证集表现远没有那么好。我先打印了前几行特征和标签发现x1那一列和标签一模一样立刻定位到是shift参数写错了。修复方法是把shift(0)改成shift(1)再重新检查每一列特征的来源日期确实早于预测日。这个坑让我养成一个习惯特征工程代码里全部写成显式的日期偏移能用日期做索引对齐就绝不用默认的行号。因为行号一旦排序、去重错位的概率非常高。4.2 坑二补缺失值时用了全局均值而不是滑动窗口第二个坑在预处理阶段。序列中间缺了几天我用整个序列的均值填补导致那几天预测曲线变得异常平缓。当时我还以为是模型问题花了好几个小时调参结果无济于事。后来我把填补后的序列可视化才发现那座“平桥”太刺眼。全局均值补进去相当于把周围正常波动抹平成同一个常数滞后特征和滚动特征都会跟着失真模型自然学到一条异常平滑的段。正确的修复方式很简单先用ffill前向填充保证连续再用interpolate对个别空洞做线性插值最后把填补的位置打一个标记特征“is_imputed”让模型自己判断这一段信息量不足。加了这个标记之后整体误差又降了一点。4.3 坑三目标变量非平稳模型预测永远落后半拍第三个坑是很多初学时序预测都会遇上的。直接用原始值训练线性回归得到的预测曲线总是“慢半拍”真实值上涨预测还在上一阶段的位置真实值到顶之后预测才开始跟着往上冲。这是典型的非平稳序列问题——目标变量有长期的上升趋势均值在随时间变化模型没法用有限的历史去外推趋势。我的排查方法是画出训练期的数据走势发现序列不但有趋势而且波动幅度也随量级变大。修复方法分两步第一步把目标变量取对数让高量级时期的波动幅度被压缩第二步在特征里加入差分项即“今天比昨天多了多少”让模型学会看增量而不是只看绝对水平。这样改造之后线性回归那条“慢半拍”的曲线明显改善树模型的效果也有进一步提升。这一步我强烈建议在复试题里主动提因为它考察的是你对时间序列平稳性概念的理解。4.4 坑四评估时用随机采样导致分数虚高第四个坑是我对比评估方式时发现的。本来我在评估阶段用的就是TimeSeriesSplit但为了试验我顺手跑了一次随机K折结果验证集MAE只有时序切分的七成。一开始我差点想把随机K折的结果写进报告幸好多画了一张图把所有预测值和真实值按时间顺序排开能看到验证期的预测曲线和真实曲线几乎重合到诡异因为验证集里的样本和训练集的样本在时间上交错模型等于见过答案。这一段踩坑经历我最后写进了答辩稿里作为“如何避免数据泄漏”的实战案例。我甚至觉得这个坑比“正确方法本身”更有教学价值因为大多数人就是栽在“看上去分数很好”上面。5. 如果把这次实战写进复试回答我会怎么组织5.1 一句话说清项目目标、数据、模型、结果复试被要求介绍项目时最忌讳的就是长篇流水账。我给自己准备了一个一句话模板照着填就行这是一个用于预测某地每日新增感染人数的回归项目基于约一年历史数据我构造了包含滞后、滚动统计和日期编码的20多个特征对比了线性回归、Ridge、随机森林和LightGBM最后用时序交叉验证验证集相对误差约在百分之十左右。这句话里包含四个要素任务、数据、方法、结果缺一不可。而且每一点后面都要准备好三分钟的展开细节但开头这30秒一定干净利落。接下来再花一分钟讲关键决策为什么不用随机划分为什么MAE比RMSE更适合作为主指标为什么需要对目标做对数变换。这三个问题基本能把深度学习之外的传统回归基础考察到。5.2 项目亮点与创新点复试项目最怕平庸但它也不需要多么花哨的创新只要体现出“我想过实验结果背后的原因”就行。我给自己提炼了三个亮点第一把数据泄漏问题当成一个正式对比案例来做在报告中同时列出随机K折和时序切分两组结果并解释为什么随机K折分数虚高。这很能体现工程严谨性。第二对目标变量做变换的选择不是拍脑门而是基于对非平稳趋势和波动异方差的观察并在验证集上比较了变换前后的差别。第三用特征重要性解释了模型行为。比如LightGBM的排序显示滚动均值特征贡献最大这说明了历史惯性在短期预测中是主导因素。讲模型结果时多讲“为什么”而不是只报数字。5.3 面试官可能追问的3个问题与应对思路我大概模拟了三个容易被追问的问题提前准备了回答思路。问题一如果让你预测未来30天方案要改吗 回答方向要改。未来30天属于中期预测直接滚动30步误差会累积得很快。我会考虑三种改进方向一是加入更多外部特征如人口流动、季节因素二是改用序列到序列的深度学习模型比如简单LSTM作为扩展对比三是报告预测区间而不是只给点预测用多次模拟或分位数回归表达不确定性。问题二你的特征里有星期几如果某个地区没有星期效应这个特征会不会有害 回答方向可能无害但可能引入噪声。树模型能在分裂时自动忽略不重要的特征但线性模型会被无关特征稀释部分信号。所以我会在特征选择阶段关注系数值若是星期特征的系数始终在0附近会把它移除再训练一次比较误差变化。问题三MAPE如果某个真实值接近0会发生什么 回答方向MAPE会爆炸。我采取的应对是同时报告MAE和RMSE而且在计算MAPE时给真实值加一个小平滑常数或者改用sMAPE用对称误差缓解分母过小的问题。这样回答既显示了数学直觉也显示了工程处理经验。5.4 复盘总结这次实战最值钱的收获不是模型准备复试到现在这个回归项目让我明白一个道理复试不是一个刷题比赛它考察的是“你会不会认真做一件小事”。预测新冠人数这个题目难度并不高任何一本机器学习教材都能教你跑通一个回归模型。但真正拉开差距的是你有没有在每一步里追问一句为什么为什么这样补缺失值为什么这个特征有意义为什么验证分数可信。我自己的实操体会是把上面那些坑一个个踩过来之后再回去看书本上的交叉验证、数据泄漏、正则化感觉完全不一样了。每个概念都有了具体的对应场景而不是一行行的数学符号。最后再分享一个小技巧每次调完一组参数我都把结果存成一个带时间戳的CSV标注当时的特征版本、模型版本和验证分数。这个习惯特别朴素但在项目复盘、写报告的时候帮了大忙。复试如果有可能被问到“你迭代过哪些版本”你可以直接从记录里挑两三个典型版本出来讲那种真实感远胜于临场编造。这一步建议你也试试。