4、特征工程:特征构建与选择、特征缩放与编码、时间序列特征提取

好,咱们进入第四章。特征工程,说白了就是「把原始数据变成模型爱吃的东西」。我见过太多人,模型调参调得飞起,结果特征一塌糊涂,最后效果就是上不去。你想想看,垃圾进垃圾出,这个道理在数据挖掘里是铁律。

在ATO系统里,原始数据往往是杂乱的日志、离散的告警、时间戳、设备ID等等。模型看不懂这些。咱们得动手,把数据「喂」成模型能消化的形态。这一章,我就带你走一遍我常用的套路。

4.1 特征构建:从无到有造特征

特征构建,不是瞎编。你得懂业务。我在ATO项目里,经常盯着告警日志发呆,然后问自己:「这个字段,能不能组合一下?」

常见的构建方法有这几类:

  • 组合特征:把两个或多个字段拼起来。比如「设备类型」+「告警级别」,能产生新的交叉特征。我习惯用 df['new_feat'] = df['col1'].astype(str) + '_' + df['col2'].astype(str) 这种写法。
  • 聚合特征:按某个维度分组,算统计量。比如按「设备ID」分组,算「过去1小时告警次数」的均值、最大值、标准差。嗯,这里要注意,聚合窗口别选太大,否则特征会滞后。
  • 业务比率特征:比如「成功交易数 / 总交易数」,这个在风控场景里特别有用。我记得有一次,光靠这个比率特征,模型AUC就涨了3个点。

核心原则:特征构建要「可解释」。别造一些连你自己都看不懂的复杂特征,上线后出了问题你根本没法排查。

4.2 特征选择:去粗取精

特征不是越多越好。我见过有人一口气造了500个特征,结果模型训练时间翻了三倍,效果反而下降了。为什么会这样?因为引入了噪声和多重共线性。

我常用的特征选择方法:

  1. 过滤法:先算每个特征与目标变量的相关性。皮尔逊相关系数、卡方检验、互信息,这些都可以。我一般设个阈值,低于0.05的直接扔掉。
  2. 包裹法:用模型来选。比如递归特征消除(RFE),每次去掉最不重要的特征。这个方法准,但计算量大。我在小数据集上常用。
  3. 嵌入法:用Lasso回归或树模型的特征重要性。LightGBM训练完,直接看 feature_importances_,一目了然。

我的小技巧:先做过滤法快速筛一遍,再用嵌入法精挑细选。这样既快又准。我曾经在一个告警预测项目里,把特征从200个砍到30个,模型效果反而提升了。

4.3 特征缩放:让数值站在同一起跑线

特征缩放,说白了就是让不同量纲的特征能公平竞争。比如「交易金额」可能是几万,「交易次数」可能是个位数。如果不缩放,模型会天然偏向数值大的特征。

两种主流方法:

方法 适用场景 公式
标准化(Z-score) 数据近似正态分布,或使用SVM、PCA等模型 (x - mean) / std
归一化(Min-Max) 数据有明确边界,或使用神经网络 (x - min) / (max - min)

我个人习惯,先用标准化。因为归一化对异常值太敏感了。你想想看,如果有个极端值,Min-Max会把其他所有值都压缩到很小一块区域,信息就丢了。

避坑指南:我曾经犯过一个错——先切分数据集,再对整个数据集做缩放。结果导致数据泄露,验证集的效果虚高。正确的做法是:先切分训练集和测试集,然后在训练集上fit缩放器,再用这个缩放器transform测试集。

4.4 特征编码:把文字变成数字

模型不认识「北京」「上海」「广州」这些字符串。你得编码。但编码方式选不对,模型会学出奇怪的关系。

常见的编码方式:

  • 独热编码:适用于类别少(比如小于10个)的情况。类别多了会维度爆炸。我一般用 pd.get_dummies(),简单粗暴。
  • 标签编码:给每个类别一个数字。比如「北京=1, 上海=2」。但要注意,模型会误以为数字之间有大小关系。所以树模型可以用,线性模型慎用。
  • 目标编码:用目标变量的均值来编码类别。比如「北京」这个城市的平均告警率。这个方法很强大,但容易过拟合。我建议配合交叉验证使用。

经验之谈:在ATO系统里,设备ID、用户ID这类高基数特征,我通常用目标编码。独热编码会生成几千列,模型根本扛不住。

4.5 时间序列特征提取:抓住时间的规律

ATO系统里,时间是最宝贵的维度。告警有周期性,交易有季节性。你得把这些规律挖出来。

我常用的时间特征:

  1. 基础时间特征:小时、星期几、月份、是否周末、是否节假日。这些直接用 dt.hourdt.weekday 就能提取。
  2. 滞后特征:比如「前1小时的告警数」「前1天的交易量」。滞后阶数怎么选?我一般用自相关图(ACF)来看。
  3. 滑动窗口统计量:过去3小时、6小时、24小时的均值、标准差、最大值、最小值。窗口大小很关键,太小了噪声大,太大了反应慢。
  4. 时间差特征:比如「距离上次告警的间隔时间」。这个在异常检测里特别好用。
# 举个例子:提取时间特征
import pandas as pd

df['timestamp'] = pd.to_datetime(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['lag_1h'] = df['alarm_count'].shift(1)

# 滑动窗口均值
df['rolling_mean_3h'] = df['alarm_count'].rolling(window=3).mean()

注意:做时间序列特征时,千万别用未来的数据。比如计算滑动窗口均值,一定要用 shift() 把当前时刻排除在外。否则就是数据泄露,模型在「偷看答案」。

嗯,这一章的内容就这些。特征工程是个细活,急不来。我每次做项目,至少花一半时间在特征上。你想想看,模型只是工具,真正决定上限的,是你对数据的理解。下一章,咱们聊聊模型选型与评估,到时候见。