1. 初识Kaggle零售销售预测挑战第一次接触Kaggle的Store Sales时间序列预测比赛时我完全被数据量吓到了。300多万条销售记录横跨54家门店、33种商品大类还要整合油价、节假日等外部因素。这可比教科书上的某城市月度用电量预测复杂多了。这个比赛的数据来自厄瓜多尔连锁超市Favorita目标是预测未来15天每家门店每种商品大类的销售额。数据包里包含几个关键文件train.csv2013-2017年的历史销售数据stores.csv门店地理位置和类型信息oil.csv每日国际油价厄瓜多尔是石油出口国holidays_events.csv当地节假日和特殊事件提示时间序列预测比赛中理解业务背景和数据关系比算法选择更重要。比如油价波动对食品销售的影响程度节假日促销的实际效果等。2. 数据清洗的实战技巧2.1 缺失值处理的正确姿势原始数据中最棘手的是oil.csv里的油价缺失。直接均值填充会失真因为油价本身波动剧烈。我的解决方案是# 前向填充可视化验证 df_oil[dcoilwtico] df_oil[dcoilwtico].fillna(methodffill) plt.plot(df_oil[date], df_oil[dcoilwtico]) plt.title(油价走势填充后)更隐蔽的坑在transactions.csv的交易额数据——测试集里该字段全是NaN。后来发现训练集中交易额为0的日子也被记录为NaN需要用0填充df_transactions.fillna(0, inplaceTrue)2.2 特征工程的组合拳合并多表数据时我设计了一套特征组合策略时空特征将门店坐标转换为区域编码捕捉地理位置影响时间分解把日期拆解成年、月、周、星期等周期性特征外部因素油价波动率、节假日类型全国性/地区性业务特征促销商品占比、门店类型组合# 时间特征生成示例 df_train[date] pd.to_datetime(df_train[date]) df_train[day_of_week] df_train[date].dt.dayofweek df_train[is_weekend] df_train[day_of_week].isin([5,6]).astype(int)3. 模型选择的进化之路3.1 从Baseline模型起步先用最简单的随机森林建立baseline发现几个关键现象MAE在70-100之间波动商品类型(family)的特征重要性最高油价影响比预期小可能需做滞后处理from sklearn.ensemble import RandomForestRegressor rf RandomForestRegressor(n_estimators100, max_depth10) rf.fit(X_train, y_train) print(fMAE: {mean_absolute_error(y_test, rf.predict(X_test))})3.2 时间序列专属特征传统机器学习模型处理时间序列的三大法宝滞后特征(Lag Features)过去7/14/28天的销售数据滚动统计(Rolling Stats)近30天均值/标准差扩展窗口(Expanding Window)历史累计平均值# 创建滞后特征 for lag in [7, 14, 21, 28]: df_train[fsales_lag_{lag}] df_train.groupby([store_nbr,family])[sales].shift(lag)3.3 梯度提升树的威力切换到XGBoost后效果显著提升关键配置xgb_params { n_estimators: 500, max_depth: 8, learning_rate: 0.05, subsample: 0.8, colsample_bytree: 0.8, objective: reg:squarederror } model xgb.XGBRegressor(**xgb_params) model.fit(X_train, y_train, eval_set[(X_test, y_test)], early_stopping_rounds20)4. 比赛提分的秘密武器4.1 目标变量变换技巧原始销售额严重右偏进行对数变换后模型效果提升15%# 对数变换1避免零值 df_train[sales] np.log1p(df_train[sales])4.2 魔法特征星期均值最有效的特征竟是该商品在该门店历史上同星期几的平均销售额weekday_avg df_train.groupby([store_nbr,family,day_of_week])[sales].mean().reset_index() weekday_avg.columns [store_nbr,family,day_of_week,weekday_avg_sales] df_train pd.merge(df_train, weekday_avg, on[store_nbr,family,day_of_week])4.3 数据筛选的玄学意外发现只用最近1年数据反而比全量数据效果更好说明消费模式会随时间演变太久远的数据可能产生噪声需要平衡数据量和数据质量recent_data df_train[df_train[date] 2016-08-15]5. 完整项目复盘与经验总结整个项目走下来最大的收获是认识到时间序列预测的复杂性。不同于结构化数据预测它需要对业务周期性的深刻理解比如厄瓜多尔每月15日和月底发薪日对销售的影响灵活的滞后特征设计不同商品可能有不同的销售周期外部因素的合理量化如何用数值表示节假日的影响程度最终我的方案在Kaggle排名前15%核心秘诀是构建了超过50个时间相关特征采用两层模型堆叠第一层预测趋势第二层修正残差对不同类型的商品食品/日用品分别建模注意比赛后期尝试了LSTM等深度学习模型但效果不如特征工程到位的XGBoost说明在数据量不够大时传统方法仍有优势。时间序列预测就像拼乐高需要把各种特征模块巧妙组合。下次如果再参加类似比赛我会更早开始做交叉验证避免在特征重要性评估上走弯路。