通过前面的学习,我们知道了机器学习的大致过程,现在要解决的问题是:如何得到训练样本?
假如数据库中有一堆数据,把这些数据转化成训练模型需要的特征的过程被称作表示法(representation)。
特征工程(Feature Engineering)
在机器学习过程中,大量的时间不是用来写代码,而是花在特征工程上。
有这么一句话在业界广泛流传:数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已。
特征工程指确定哪些特征可能在训练模型方面非常有用,然后将日志文件及其他来源的原始数据转换为所需的特征。因为机器学习能处理的是数值,因此转换的结果是由实数组成的特征矢量。
在实际操作中我们手头的数据类型多种多样,要根据不同类型做不同的处理:
数值
不需要做处理。
字符串
我们自然会想到使用枚举值来代替字符串。比如有个字段名是街道名,包含三个值:文一西路、常二路、文二路,我们会想到用 1, 2, 3 来表示三个值。但是这样有一个问题:学习算法会认为这三个值是有顺序或者有大小区别的。
因此我们对于无序的字符串,会使用独热编码(one-hot encoding)来转化。
独热编码即 One-Hot 编码,又称一位有效编码,其方法是使用 N 位状态寄存器来对 N 个状态进行编码,每个状态都由他独立的寄存器位,并且在任意时候,其中只有一位有效。
对于前面的例子,转化结果如下:
[“文一西路”, “常二路”, “文二路”] => [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
枚举值
比如有一组用户喜欢的水果数据,可能的值有苹果、香蕉、桃。类似于字符串,我们用三个布尔值组合起来表示。与独热编码不同的是:我们允许其中的多个值同时为真(用户同时喜欢苹果和香蕉)。
挑选特征
知道了如何转换特征之后,我们要知道如何挑选合适的特征,合适的特征应该是什么样的呢?
- 不能太过独特:比如每个用户的 ID 都是不同的,学习算法无法从中学习任何规律。
- 含义明确:数据容易让人理解,不能超出常识范围。比如温度值为 -300 度显然是无效的数据。
- 不包含 magic number:我们写程序的时候可能会设置一些 magic number 来表示一些不同的状态,比如用 -1 表示数据不存在。这样的数据不应该直接放到特征向量中,而应该拆分成两个值,一个表示数据是否存在,一个表示实际的数据。
- 数据上游应该稳定:不应该选取可能随时间变化的值来作为特征。
清理数据
在把样本提供给学习算法训练之前,需要对数据进行一些加工,让训练的速度更快、模型的预测更准确。
无效数据
从数据源得到的数据并不一定是完全准确的,也不一定是适合机器学习算法的,常见的错误有:
- 遗漏数据。
- 重复样本。
- 错误的标签。
- 错误的特征值。
统计一下数据的最大、最小值、均值等数据可能会快速找到这些无效的数据。
缩放特征值
缩放是指将浮点特征值从自然范围(例如 100 到 900)转换为标准范围(例如 0 到 1 或 -1 到 +1)。
缩放的好处是:
- 可以让梯度下降法更快收敛。
- 避免学习算法因为精度或者数值范围问题得到奇怪的结果。
- 帮助模型为每个特征确定合适的权重。如果没有进行特征缩放,则模型会对范围较大的特征投入过多精力。
处理极端离群值
对于某些明显偏离正常范围的值,我们可以:
- 对每个值取对数。
- 设置最大值,超过最大值数据的都调整为最大值。
分箱(Bucketing)
将一个特征(通常是连续特征)转换成多个二元特征(称为桶或箱),通常是根据值区间进行转换。例如,您可以将温度区间分割为离散分箱,而不是将温度表示成单个连续的浮点特征。假设温度数据可精确到小数点后一位,则可以将介于 0.0 到 15.0 度之间的所有温度都归入一个分箱,将介于 15.1 到 30.0 度之间的所有温度归入第二个分箱,并将介于 30.1 到 50.0 度之间的所有温度归入第三个分箱。
这样做的好处是:
- 离散化结果将会减少给定连续特征值的个数,减小系统对存储空间的实际需求。
- 离散特征相对于连续特征来说更接近于知识层面的表示。
- 通过离散化,数据被规约和简化,对于使用者和专家来说,离散化的数据都更易于理解,使用和解释。
- 离散化处理使得算法的学习更为准确和迅速。
- 一系列算法只能应用于离散型数据,使得离散化处理成为必要,而离散化又使很多算法的应用范围扩展了。