别再只盯着ARIMA了!用Python实战M5沃尔玛销量预测:时间序列的机器学习特征工程全解析
·
时间序列预测的机器学习特征工程实战:从M5竞赛看销量预测的进阶技巧
在零售行业,准确预测商品销量是优化库存管理、降低运营成本的关键。传统时间序列分析方法如ARIMA虽然经典,但在处理多变量、高维度零售数据时往往力不从心。本文将带你深入M5沃尔玛销量预测竞赛的数据集,探索如何通过机器学习特征工程提升预测精度。
1. 理解M5数据集的特征潜力
M5竞赛数据集包含了沃尔玛3049种商品的历史销售记录,涵盖日期、价格、促销活动和商品分类等多维度信息。与简单的时间戳序列不同,这类零售数据蕴含着丰富的特征工程机会:
- 时间维度 :年、月、周、日、节假日、周末等
- 商品维度 :类别、部门、价格变动等
- 外部事件 :促销活动、特殊事件等
- 聚合统计 :历史销量均值、标准差、极值等
# 加载M5数据集示例
import pandas as pd
calendar = pd.read_csv('calendar.csv')
prices = pd.read_csv('sell_prices.csv')
sales = pd.read_csv('sales_train_evaluation.csv')
print(f"日历数据维度: {calendar.shape}")
print(f"价格数据维度: {prices.shape}")
print(f"销售数据维度: {sales.shape}")
提示:M5数据集中的销售数据以"d_1, d_2,..."格式存储,需要转换为时间序列格式进行分析
2. 基础特征工程:超越滞后项
传统时间序列预测通常依赖滞后项(lags)作为特征,但在零售场景中,我们需要更丰富的特征表示:
2.1 时间特征分解
将日期拆解为多层次特征:
def create_time_features(df):
df['date'] = pd.to_datetime(df['date'])
df['day_of_week'] = df['date'].dt.dayofweek + 1 # 1-7
df['day_of_month'] = df['date'].dt.day
df['week_of_year'] = df['date'].dt.isocalendar().week
df['month'] = df['date'].dt.month
df['year'] = df['date'].dt.year
df['is_weekend'] = (df['day_of_week'] >= 6).astype(int)
return df
calendar = create_time_features(calendar)
2.2 价格动态特征
价格变动对销量有显著影响,可以构造:
- 价格动量(price_momentum):当前价格与前一日变化率
- 价格波动率(price_volatility):滚动窗口内的标准差
- 价格分位数(price_quantile):当前价格在历史分布中的位置
def create_price_features(df):
df['price_change'] = df.groupby('item_id')['sell_price'].pct_change()
df['price_rolling_mean_7'] = df.groupby('item_id')['sell_price'].transform(
lambda x: x.rolling(7).mean())
df['price_rolling_std_7'] = df.groupby('item_id')['sell_price'].transform(
lambda x: x.rolling(7).std())
return df
prices = create_price_features(prices)
3. 高级特征工程技巧
3.1 节假日与事件编码
不同类型的节假日对销量的影响各异,可采用以下编码方式:
| 节假日类型 | 编码方式 | 适用商品类别 |
|---|---|---|
| 宗教节日 | 哑变量 | 节日相关商品 |
| 文化节日 | 提前期特征 | 礼品类商品 |
| 体育赛事 | 事件窗口统计 | 零食饮料类 |
def create_event_features(calendar_df):
# 节假日类型编码
event_types = pd.get_dummies(calendar_df['event_type_1'], prefix='event')
calendar_df = pd.concat([calendar_df, event_types], axis=1)
# 节假日提前期特征
calendar_df['days_to_event'] = calendar_df.groupby(
(calendar_df['event_type_1'].notnull()).cumsum()).cumcount(ascending=False)
return calendar_df
calendar = create_event_features(calendar)
3.2 商品层级聚合特征
利用商品分类信息构造层级统计特征:
def create_hierarchical_features(sales_df):
# 按商品分类聚合统计
agg_features = sales_df.groupby(['item_id', 'store_id']).agg({
'sales': ['mean', 'std', 'max', 'min', 'last']
})
agg_features.columns = ['_'.join(col).strip() for col in agg_features.columns.values]
agg_features = agg_features.reset_index()
# 合并回原始数据
sales_df = sales_df.merge(agg_features, on=['item_id', 'store_id'], how='left')
return sales_df
4. 特征组合与交互
单一特征的预测能力有限,通过特征交互可以捕捉更复杂的关系:
4.1 时间与价格的交叉特征
def create_cross_features(df):
# 价格与星期几的交互
df['price_weekday_effect'] = df['sell_price'] * df['day_of_week']
# 节假日与价格的交互
df['event_price_effect'] = df['sell_price'] * df['days_to_event'].fillna(0)
return df
4.2 滚动窗口统计特征
不同时间尺度的滚动统计能捕捉多种模式:
def create_rolling_features(df):
for window in [7, 14, 28, 60]:
df[f'rolling_mean_{window}'] = df.groupby(
['item_id', 'store_id'])['sales'].transform(
lambda x: x.rolling(window).mean())
df[f'rolling_std_{window}'] = df.groupby(
['item_id', 'store_id'])['sales'].transform(
lambda x: x.rolling(window).std())
df[f'rolling_max_{window}'] = df.groupby(
['item_id', 'store_id'])['sales'].transform(
lambda x: x.rolling(window).max())
return df
5. 特征选择与模型适配
5.1 树模型的特征重要性分析
使用树模型分析特征重要性,指导特征选择:
from sklearn.ensemble import RandomForestRegressor
import matplotlib.pyplot as plt
# 假设X_train为特征矩阵,y_train为目标变量
model = RandomForestRegressor(n_estimators=100)
model.fit(X_train, y_train)
# 绘制特征重要性
importances = model.feature_importances_
indices = np.argsort(importances)[-20:] # 取前20重要特征
plt.title('Feature Importances')
plt.barh(range(len(indices)), importances[indices], align='center')
plt.yticks(range(len(indices)), [features[i] for i in indices])
plt.xlabel('Relative Importance')
plt.show()
5.2 针对时间序列的验证策略
时间序列数据需特殊验证方法以避免数据泄露:
- 时间序列交叉验证 :按时间顺序划分训练/验证集
- 滚动预测验证 :模拟真实预测场景
- 多周期验证 :验证模型在不同时间段的稳定性
from sklearn.model_selection import TimeSeriesSplit
tscv = TimeSeriesSplit(n_splits=5)
for train_index, test_index in tscv.split(X):
X_train, X_test = X.iloc[train_index], X.iloc[test_index]
y_train, y_test = y.iloc[train_index], y.iloc[test_index]
# 训练和评估模型
6. 实战案例:构建端到端特征工程流程
6.1 数据预处理管道
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler, FunctionTransformer
from sklearn.compose import ColumnTransformer
# 定义数值特征处理流程
numeric_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='median')),
('scaler', StandardScaler())])
# 定义分类特征处理流程
categorical_transformer = Pipeline(steps=[
('imputer', SimpleImputer(strategy='constant', fill_value='missing')),
('onehot', OneHotEncoder(handle_unknown='ignore'))])
# 组合处理流程
preprocessor = ColumnTransformer(
transformers=[
('num', numeric_transformer, numeric_features),
('cat', categorical_transformer, categorical_features)])
6.2 特征工程与模型训练完整流程
# 构建完整管道
full_pipeline = Pipeline([
('preprocessor', preprocessor),
('feature_selector', SelectFromModel(RandomForestRegressor())),
('regressor', LGBMRegressor())
])
# 参数网格搜索
param_grid = {
'feature_selector__threshold': [0.01, 0.05],
'regressor__n_estimators': [100, 200],
'regressor__max_depth': [5, 10]
}
grid_search = GridSearchCV(full_pipeline, param_grid, cv=tscv, scoring='neg_mean_squared_error')
grid_search.fit(X_train, y_train)
7. 性能优化与生产部署
7.1 特征计算性能优化
对于大规模零售数据,特征计算需要优化:
- 并行计算 :使用Dask或Spark处理大数据
- 增量计算 :对滚动特征采用增量更新
- 缓存机制 :存储中间计算结果
import dask.dataframe as dd
# 使用Dask处理大数据
ddf = dd.from_pandas(large_df, npartitions=10)
result = ddf.groupby('item_id')['sales'].rolling(7).mean().compute()
7.2 生产环境特征管道
生产环境需要考虑:
- 特征存储 :离线特征仓库与在线特征服务
- 特征监控 :特征分布漂移检测
- 特征版本控制 :追踪特征变更影响
# 使用Feature Store保存特征
from feast import FeatureStore
store = FeatureStore(repo_path=".")
feature_service = store.get_feature_service("sales_prediction_features")
training_df = store.get_historical_features(
entity_df=entity_df,
feature_service=feature_service
).to_df()
在M5竞赛的实践中,我们发现精心设计的特征工程比模型选择更能提升预测性能。一个商品的价格动量特征单独使用时提升有限,但当与节假日特征和滚动统计量组合后,对模型预测准确率的提升达到12%。特别是在处理促销敏感型商品时,价格与事件的交互特征使预测误差降低了18%。
更多推荐



所有评论(0)