3. 特征工程基础:时间特征提取、统计特征构建、业务特征衍生

特征工程,说白了就是给模型喂「对的数据」。我见过太多人一上来就堆几百个特征,结果模型过拟合得一塌糊涂。其实在订单流预测里,真正有用的特征就那么几类——时间、统计、业务。咱们一个一个拆开讲。

3.1 时间特征提取:把「什么时候」变成数字

模型不懂「上午十点」是什么意思,它只认数字。所以第一步,就是把时间戳拆成模型能理解的东西。

基础时间特征

  • 小时、分钟、星期几、月份
  • 是否周末、是否节假日
  • 一年中的第几天、第几周

举个例子,我做过一个外卖订单预测项目。一开始只用了小时和星期几,效果一般。后来加了「是否下雨」「是否工作日」这些特征,准确率直接提升了8%。你想想看,下雨天大家都不爱出门,订单量自然暴涨。

核心思路:时间特征要能反映周期性。比如「小时」是24小时周期,「星期几」是7天周期。模型需要这些周期信号来捕捉规律。

代码示例

import pandas as pd
import numpy as np

# 假设df['timestamp']是时间戳列
df['hour'] = df['timestamp'].dt.hour
df['day_of_week'] = df['timestamp'].dt.dayofweek
df['is_weekend'] = df['day_of_week'].isin([5, 6]).astype(int)
df['day_of_year'] = df['timestamp'].dt.dayofyear
df['week_of_year'] = df['timestamp'].dt.isocalendar().week.astype(int)

小技巧:我个人习惯把「小时」做sin/cos变换。因为23点和0点其实很近,但直接编码成23和0,模型会以为它们差很远。用sin/cos就能保留这种循环关系。

3.2 统计特征构建:从历史中找规律

统计特征,说白了就是「过去发生了什么」。模型需要知道:过去1小时订单量多少?过去7天平均订单量多少?这些信息能帮它预测未来。

常用统计特征

  • 滚动均值、滚动标准差
  • 最大值、最小值、中位数
  • 过去N期的累计和
  • 环比、同比变化率

我记得有一次做股票订单流预测,发现单纯用价格特征效果很差。后来加了「过去5分钟订单量的标准差」——这个特征直接反映了市场波动性。嗯,模型一下子就开窍了。

避坑指南:我曾经犯过一个低级错误——用未来数据算统计特征。比如用「当天全天的平均订单量」来预测当天下午的订单。这属于数据泄露,模型在测试集上表现完美,一上线就崩。切记:统计窗口必须严格限制在「当前时刻之前」。

代码示例

# 滚动统计:过去1小时(假设数据是分钟级)
df['rolling_mean_60'] = df['order_count'].rolling(window=60).mean()
df['rolling_std_60'] = df['order_count'].rolling(window=60).std()
df['rolling_max_60'] = df['order_count'].rolling(window=60).max()

# 环比变化率
df['change_rate'] = df['order_count'].pct_change(periods=1)

# 同比:与昨天同一时刻对比
df['yoy_change'] = df['order_count'] / df['order_count'].shift(1440) - 1  # 1440分钟=1天

3.3 业务特征衍生:把「领域知识」塞进模型

这是最值钱的部分。通用特征谁都会做,但业务特征才是你的护城河。说白了,就是把你对这个行业的理解,转化成模型能用的数字。

常见的业务特征思路

  • 促销活动:是否在促销期间?距离上次促销多久?
  • 库存状态:当前库存水平、库存周转率
  • 用户行为:用户平均下单间隔、最近一次下单时间
  • 外部因素:天气、节假日、竞品动态

举个例子,我在做电商订单流预测时,发现「距离上次大促的天数」这个特征特别有用。大促刚结束那几天,订单量会断崖式下跌,然后慢慢恢复。模型如果不理解这个规律,就会一直高估订单量。

核心原则:业务特征要能解释「异常波动」。比如突然的订单暴增,可能是因为限时秒杀,而不是正常的周期性波动。模型需要知道这个「原因」。

代码示例

# 促销活动特征
df['is_promotion'] = (df['timestamp'].isin(promotion_dates)).astype(int)
df['days_since_last_promotion'] = (df['timestamp'] - last_promotion_date).dt.days

# 库存特征
df['stock_level'] = df['current_stock'] / df['max_stock']  # 库存饱和度
df['stock_turnover'] = df['sales_volume'] / df['average_stock']  # 周转率

# 用户行为特征
df['avg_order_interval'] = df.groupby('user_id')['timestamp'].diff().mean()
df['days_since_last_order'] = (df['timestamp'] - df.groupby('user_id')['timestamp'].shift(1)).dt.days

3.4 特征选择与降维:别让模型「消化不良」

特征不是越多越好。我见过有人做了200多个特征,结果模型训练时间翻了三倍,效果反而下降了。为什么会这样?因为很多特征之间高度相关,模型学到的都是重复信息。

常用方法

  • 相关性分析:剔除相关系数大于0.95的特征对
  • 特征重要性:用随机森林或XGBoost筛选Top-K特征
  • PCA降维:把高维特征压缩成几个主成分

我的习惯:先做一轮相关性分析,把明显冗余的特征去掉。然后用模型跑一次特征重要性,保留前30-50个特征。最后用PCA做二次降维,把维度控制在20以内。这样既保留了信息,又不会过拟合。

代码示例

from sklearn.ensemble import RandomForestRegressor
from sklearn.decomposition import PCA

# 特征重要性筛选
model = RandomForestRegressor(n_estimators=100)
model.fit(X_train, y_train)
importance = pd.DataFrame({
    'feature': X_train.columns,
    'importance': model.feature_importances_
}).sort_values('importance', ascending=False)

# 保留Top-30特征
top_features = importance.head(30)['feature'].tolist()
X_selected = X_train[top_features]

# PCA降维
pca = PCA(n_components=20)
X_pca = pca.fit_transform(X_selected)

3.5 特征工程全流程框架

下面这张图是我自己总结的特征工程流程,每次做项目都按这个来。你照着走,基本不会漏掉关键步骤。

特征工程全流程框架 原始数据 时间特征提取 统计特征构建 业务特征衍生 特征筛选与降维 最终特征集

这张图的核心逻辑是:原始数据进来后,分三条路并行处理——时间、统计、业务。最后合并到一起,做一轮筛选降维,得到最终特征集。每一步都有坑,但按这个框架走,至少不会跑偏。

最后提醒一句:特征工程没有银弹。同样的特征,换一个数据集可能就失效了。我的建议是:先做一轮快速实验,看看哪些特征贡献最大,然后集中精力优化那部分。别一开始就追求完美,迭代才是王道。


专注资料整理