4、特征工程(上):数值型特征处理与类别型特征编码

大家好,欢迎来到特征工程的上半部分。说实话,在机器学习这条路上摸爬滚打这么多年,我越来越觉得:数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已。今天咱们就来聊聊数值型特征怎么处理,类别型特征怎么编码。

4.1 数值型特征处理

数值型特征,说白了就是那些能直接加减乘除的数字。比如年龄、收入、温度。但原始数据往往「不干净」,需要我们先处理一下。

4.1.1 标准化(Standardization)

标准化的核心思想是:把数据变成均值为0、标准差为1的分布。公式很简单:

z = (x - μ) / σ

其中 μ 是均值,σ 是标准差。

我个人习惯在 SVM、逻辑回归、神经网络 这类对特征尺度敏感的模型上,必须做标准化。为什么?你想想看,如果一个特征是年龄(0-100),另一个特征是收入(0-100000),收入这个特征天然就会主导模型训练,这不合理。

重要提醒:标准化后的数据不是正态分布,只是变成了标准正态分布的形状。如果你的数据本身是偏态的,标准化后依然是偏态的。

我在项目中遇到过这样一个坑:有个金融风控项目,特征「交易金额」的分布极其右偏。标准化之后,大部分数据都集中在 -0.5 到 0.5 之间,但有几个大额交易直接跑到了 10 以上。模型训练时,这几个异常点把整个决策边界都带偏了。后来我用了 RobustScaler 才解决。

4.1.2 归一化(Normalization)

归一化是把数据缩放到 [0, 1] 区间。最常用的是 Min-Max 归一化:

x_norm = (x - x_min) / (x_max - x_min)

什么时候用归一化?当你知道数据的上下界是明确的、稳定的。比如像素值 0-255,考试成绩 0-100。

注意:如果数据有新的最大值或最小值出现,归一化后的结果会「漂移」。我曾经在一个实时推荐系统里用归一化处理用户活跃度,结果某天一个超级活跃用户出现,导致所有老用户的活跃度都被压缩到了 0.1 以下,推荐效果直接崩了。从那以后,我对于在线系统更倾向于用标准化。

标准化 vs 归一化,怎么选?我一般这样判断:

场景 推荐方法 原因
数据有明确上下界 归一化 保持原始比例关系
数据有异常值 标准化(或 RobustScaler) 不受极值影响
模型需要距离计算 标准化 各特征贡献均衡
稀疏数据 保持原样或归一化 标准化会破坏稀疏性

4.1.3 离散化(Discretization)

离散化就是把连续值切成几个「桶」。比如年龄 0-100 变成「少年、青年、中年、老年」。

常用的方法有三种:

  1. 等宽离散化:把数据范围等分成 k 份。比如 0-100 分成 5 份,每份 20 个单位。
  2. 等频离散化:每个桶里放相同数量的样本。适合数据分布不均匀的情况。
  3. 基于聚类:用 K-Means 把数据聚成 k 类,每类一个桶。

嗯,这里要注意:离散化会丢失信息。你想想看,原本精确的 25 岁和 26 岁,离散化后可能都在「青年」这个桶里,模型就分不清了。所以除非有明确业务含义(比如年龄分段定价),否则我一般不建议轻易离散化。

我的经验:在树模型(随机森林、XGBoost)中,离散化往往没什么帮助,因为树模型自己就能找到最优切分点。但在线性模型中,离散化有时能带来非线性表达能力,效果反而更好。

4.2 类别型特征编码

类别型特征,就是那些不能直接做加减乘除的。比如颜色(红、黄、蓝)、城市(北京、上海、广州)。模型不认识「红」这个字,它只认识数字。所以我们需要编码。

4.2.1 One-Hot 编码

One-Hot 是最直观的方法:有 k 个类别,就创建 k 个 0/1 特征。比如颜色有红、黄、蓝三种:

红色 → [1, 0, 0]
黄色 → [0, 1, 0]
蓝色 → [0, 0, 1]

优点很明显:类别之间没有大小关系,互不干扰。缺点也很明显:维度爆炸。如果某个特征有 1000 个类别,那就多出 1000 列。

我曾经在一个电商推荐项目里,商品类目有 5000 多个。直接 One-Hot 后,特征矩阵从 50 列变成了 5050 列,训练时间从 2 分钟变成了 2 小时。后来我用了两个技巧:

  • 低频合并:出现次数少于 10 次的类别,统一归为「其他」
  • Hash Trick:用哈希函数把类别映射到固定长度的向量

4.2.2 Label Encoding

Label Encoding 就是给每个类别一个整数编号:红=0,黄=1,蓝=2。

听起来很简单对吧?但这里有个大坑:模型会认为类别之间有大小关系。比如模型可能学到「蓝色 > 黄色 > 红色」,这完全没道理。

我曾经踩过的坑:在一个房价预测项目中,我把「户型」做了 Label Encoding:一居室=0,两居室=1,三居室=2,四居室=3。结果模型学到的权重是正的,认为户型数字越大房价越高。但实际数据中,五居室(编码=4)的房价反而低于三居室,因为五居室大多是老房子。这就是 Label Encoding 带来的虚假顺序关系。

那什么时候用 Label Encoding?当类别本身有顺序关系时。比如教育程度:小学 < 中学 < 大学 < 研究生。或者评分等级:差=0,中=1,良=2,优=3。

另外,树模型对 Label Encoding 比较友好。因为树模型做的是条件判断(if x > 0.5),它不会像线性模型那样把编码值当成连续值来算权重。所以如果你用 XGBoost 或 LightGBM,Label Encoding 通常没问题。

4.2.3 其他编码方式(简单提一下)

除了上面两种,还有几种编码方式,大家了解一下:

编码方式 适用场景 特点
Target Encoding 高基数类别特征 用目标变量的均值代替类别,容易过拟合
Frequency Encoding 类别出现频率有业务意义 用类别出现次数代替,简单有效
Binary Encoding 类别数量中等(几十到几百) 先用整数编码,再转二进制,维度比 One-Hot 少

4.3 实战建议

说了这么多,最后给几个实战中的小建议:

  1. 先分析数据分布:不要上来就标准化或归一化。先画个直方图看看数据长什么样。
  2. 区分模型类型:线性模型、神经网络需要标准化;树模型不需要。
  3. 类别特征优先用 One-Hot:除非类别数太多(比如超过 100),或者类别有顺序关系。
  4. 注意数据泄露:标准化、归一化的参数(均值、标准差、最大最小值)只能用训练集计算,然后应用到验证集和测试集。千万不要用全量数据计算。

好了,数值型特征和类别型特征的处理就讲到这里。下一节我们会聊文本特征、时间特征和特征交叉,这些都是实际项目中经常遇到的。咱们下期见。