Google机器学习教程笔记(二)#
前面谈到了数据集合的划分,接下来我们开始谈一下如何获得我们想要的特征集。
特征工程
将原始数据映射到特征
图1左侧表示来自输入数据源的原始数据,右侧表示特征矢量,也就是组成数据集中样本的浮点值集。 特征工程指的是将原始数据转换为特征矢量。进行特征工程预计需要大量时间。
机器学习模型通常期望样本表示为实数矢量。这种矢量的构建方法如下:为每个字段衍生特征,然后将它们全部连接到一起。
映射数值
机器学习模型根据浮点值进行训练,因此整数和浮点原始数据不需要特殊编码。正如图 2 所示,将原始整数值 6 转换为特征值 6.0 是没有意义的:
映射字符串值
模型无法通过字符串值学习规律,因此您需要进行一些特征工程来将这些值转换为数字形式:
1.首先,为您要表示的所有特征的字符串值定义一个词汇表。对于 street_name 特征,该词汇表中将包含您知道的所有街道。
2.然后,使用该词汇表创建一个独热编码,用于将指定字符串值表示为一个二元矢量。在该矢量(与指定的字符串值对应)中:
- 只有一个元素设为 1。
- 其他所有元素均设为 0。
该矢量的长度等于词汇表中的元素数。
图3显示了某条特定街道 (Shorebird Way) 的独热编码。在此二元矢量中,代表 Shorebird Way 的元素的值为1,而代表所有其他街道的元素的值为 0。
映射分类(枚举)值
分类特征具有一组离散的可能值。例如,名为 Lowland Countries 的特征只包含 3 个可能值:
{‘Netherlands’, ‘Belgium’, ‘Luxembourg’}
您可能会将分类特征(如 Lowland Countries)编码为枚举类型或表示不同值的整数离散集。例如:
- 将荷兰表示为 0
- 将比利时表示为 1
- 将卢森堡表示为 2
不过,机器学习模型通常将每个分类特征表示为单独的布尔值。例如,Lowland Countries 在模型中可以表示为 3 个单独的布尔值特征:
- x1:是荷兰吗?
- x2:是比利时吗?
- x3:是卢森堡吗?
采用这种方法编码还可以简化某个值可能属于多个分类这种情况(例如,“与法国接壤”对于比利时和卢森堡来说都是 True)。
良好特征的特点
我们探索了将原始数据映射到合适特征矢量的方法,但这只是工作的一部分。现在,我们必须探索什么样的值才算这些特征矢量中良好的特征。
- 避免很少使用的离散特征值
- 最好具有清晰明确的含义
- 不要将奇异值与实际数据混为一谈(例如某项数据用户没有输入):为了解决奇异值的问题需要将该特征转换为两个特征:(1)一个特征只存储实际值,不包含奇异值(2)一个特征存储布尔值,表示是否存在该值
数据清理
缩放特征值
缩放是指将浮点特征值从自然范围(例如 100 到 900)转换为标准范围(例如 0 到 1 或 -1 到 +1)。如果某个特征集只包含一个特征,则缩放可以提供的实际好处微乎其微或根本没有。不过,如果特征集包含多个特征,则缩放特征可以带来以下优势:
-
帮助梯度下降法更快速地收敛。
-
帮助避免“NaN 陷阱”。在这种陷阱中,模型中的一个数值变成 NaN(例如,当某个值在训练期间超出浮点精确率限制时),并且模型中的所有其他数值最终也会因数学运算而变成 NaN。
-
帮助模型为每个特征确定合适的权重。如果没有进行特征缩放,则模型会对范围较大的特征投入过多精力。
不需要对每个浮点特征进行完全相同的缩放。即使特征 A 的范围是 -1 到 +1,同时特征 B 的范围是 -3 到 +3,也不会产生什么恶劣的影响。不过,如果特征 B 的范围是 5000 到 100000,模型会出现糟糕的响应。
处理极端离群值
下面的曲线图表示的是加利福尼亚州住房数据集中称为 roomsPerPerson 的特征。roomsPerPerson 值的计算方法是相应地区的房间总数除以相应地区的人口总数。该曲线图显示,在加利福尼亚州的绝大部分地区,人均房间数为 1 到 2 间。不过,请看一下 x 轴。
如何最大限度降低这些极端离群值的影响?一种方法是对每个值取对数:
对数缩放可稍稍缓解这种影响,但仍然存在离群值这个大尾巴。我们来采用另一种方法。如果我们只是简单地将 roomsPerPerson 的最大值“限制”为某个任意值(比如 4.0),会发生什么情况呢?
将特征值限制到 4.0 并不意味着我们会忽略所有大于 4.0 的值。而是说,所有大于 4.0 的值都将变成 4.0。这就解释了 4.0 处的那个有趣的小峰值。尽管存在这个小峰值,但是缩放后的特征集现在依然比原始数据有用。
分箱
下面的曲线图显示了加利福尼亚州不同纬度的房屋相对普及率。注意集群 - 洛杉矶大致在纬度 34 处,旧金山大致在纬度 38 处。
在数据集中,latitude 是一个浮点值。不过,在我们的模型中将 latitude 表示为浮点特征没有意义。这是因为纬度和房屋价值之间不存在线性关系。例如,纬度 35 处的房屋并不比纬度 34 处的房屋贵 35/34(或更便宜)。但是,纬度或许能很好地预测房屋价值。
为了将纬度变为一项实用的预测指标,我们对纬度“分箱”,如下图所示:
我们现在拥有 11 个不同的布尔值特征(LatitudeBin1、LatitudeBin2、…、LatitudeBin11),而不是一个浮点特征。拥有 11 个不同的特征有点不方便,因此我们将它们统一成一个 11 元素矢量。这样做之后,我们可以将纬度 37.4 表示为:[0,0,0,0,0,1,0,0,0,0,0]
分箱之后,我们的模型现在可以为每个纬度学习完全不同的权重。
为了简单起见,我们在纬度样本中使用整数作为分箱边界。如果我们需要更精细的解决方案,我们可以每隔 1/10 个纬度拆分一次分箱边界。添加更多箱可让模型从纬度 37.4 处学习和维度 37.5 处不一样的行为,但前提是每 1/10 个纬度均有充足的样本可供学习。
另一种方法是按分位数分箱,这种方法可以确保每个桶内的样本数量是相等的。按分位数分箱完全无需担心离群值。
清查
截至目前,我们假定用于训练和测试的所有数据都是值得信赖的。在现实生活中,数据集中的很多样本是不可靠的,原因有以下一种或多种:
- 遗漏值。 例如,有人忘记为某个房屋的年龄输入值。
- 重复样本。 例如,服务器错误地将同一条记录上传了两次。
- 不良标签。 例如,有人错误地将一颗橡树的图片标记为枫树。
- 不良特征值。 例如,有人输入了多余的位数,或者温度计被遗落在太阳底下。
一旦检测到存在这些问题,您通常需要将相应样本从数据集中移除,从而“修正”不良样本。要检测遗漏值或重复样本,您可以编写一个简单的程序。检测不良特征值或标签可能会比较棘手。
除了检测各个不良样本之外,您还必须检测集合中的不良数据。直方图是一种用于可视化集合中数据的很好机制。此外,收集如下统计信息也会有所帮助:
- 最大值和最小值
- 均值和中间值
- 标准偏差
了解数据
遵循以下规则:
- 记住您预期的数据状态。
- 确认数据是否满足这些预期(或者您可以解释为何数据不满足预期)。
- 仔细检查训练数据是否与其他来源(例如信息中心)的数据一致。
像处理任何任务关键型代码一样谨慎处理您的数据。良好的机器学习依赖于良好的数据。
特征组合
当解决非线性问题的时候,可以创建一个特征组合。特征组合是指通过将两个或多个输入特征相乘来对特征空间中的非线性规律进行编码的合成特征。“cross”(组合)这一术语来自 cross product(向量积)。我们通过将x1与x2组合来创建一个名为x2的特征组合:
我们像处理任何其他特征一样来处理这个新建的x3特征组合。线性公式变为:
线性算法可以算出w3的权重,就像算出w1和w2的权重一样。换言之,虽然w3表示非线性信息,但您不需要改变线性模型的训练方式来确定w3的值.
解决过拟合:正则化
看看一下迭代曲线,该曲线显示的是训练集和验证集相对于训练迭代次数的损失。
图 1 显示的是某个模型的训练损失逐渐减少,但验证损失最终增加。换言之,该泛化曲线显示该模型与训练集中的数据过拟合。或许我们可以通过降低复杂模型的复杂度来防止过拟合,这种原则称为正则化。
也就是说,并非只是以最小化损失(经验风险最小化)为目标:
而是以最小化损失和复杂度为目标,这称为结构风险最小化:
现在,我们的训练优化算法是一个由两项内容组成的函数:一个是损失项,用于衡量模型与数据的拟合度,另一个是正则化项,用于衡量模型复杂度。
机器学习速成课程重点介绍了两种衡量模型复杂度的常见方式(这两种方式有些相关):
-
将模型复杂度作为模型中所有特征的权重的函数。
-
将模型复杂度作为具有非零权重的特征总数的函数。(后面的一个单元介绍了这种方法。)
如果模型复杂度是权重的函数,则特征权重的绝对值越高,模型就越复杂。
我们可以使用 L2 正则化公式来量化复杂度,该公式将正则化项定义为所有特征权重的平方和:
在这个公式中,接近于 0 的权重对模型复杂度几乎没有影响,而离群值权重则可能会产生巨大的影响。
正则化系数lambda
模型开发者通过以下方式来调整正则化项的整体影响:用正则化项的值乘以名为 lambda(又称为正则化率)的标量。也就是说,模型开发者会执行以下运算:
执行 L2 正则化对模型具有以下影响
- 使权重值接近于 0(但并非正好为 0)
- 使权重的平均值接近于 0,且呈正态(钟形曲线或高斯曲线)分布。
增加 lambda 值将增强正则化效果。 例如,lambda 值较高的权重直方图可能会如图2 所示。
降低 lambda 的值往往会得出比较平缓的直方图,如图3 所示。
在选择 lambda 值时,目标是在简单化和训练数据拟合之间达到适当的平衡:
-
如果您的 lambda 值过高,则模型会非常简单,但是您将面临数据欠拟合的风险。您的模型将无法从训练数据中获得足够的信息来做出有用的预测。
-
如果您的 lambda 值过低,则模型会比较复杂,并且您将面临数据过拟合的风险。您的模型将因获得过多训练数据特点方面的信息而无法泛化到新数据。
注意:将 lambda 设为 0 可彻底取消正则化。 在这种情况下,训练的唯一目的将是最小化损失,而这样做会使过拟合的风险达到最高。
L2正则化和Learning Rate
学习速率和 lambda 之间存在密切关联。强 L2 正则化值往往会使特征权重更接近于 0。较低的学习速率(使用早停法)通常会产生相同的效果,因为与 0 的距离并不是很远。 因此,同时调整学习速率和 lambda 可能会产生令人混淆的效果。
早停法指的是在模块完全收敛之前就结束训练。在实际操作中,我们经常在以在线(连续)方式进行训练时采取一些隐式早停法。也就是说,一些新趋势的数据尚不足以收敛。
如上所述,更改正则化参数产生的效果可能会与更改学习速率或迭代次数产生的效果相混淆。一种有用的做法(在训练一批固定的数据时)是执行足够多次迭代,这样早停法便不会起作用。
L1正则化:解决稀疏性
稀疏矢量通常包含许多维度。创建特征组合会导致包含更多维度。由于使用此类高维度特征矢量,因此模型可能会非常庞大,并且需要大量的 RAM。在高维度稀疏矢量中,最好尽可能使权重正好降至 0。正好为 0 的权重基本上会使相应特征从模型中移除。 将特征设为 0 可节省 RAM 空间,且可以减少模型中的噪点。
即我们需要有一种正则化方式,来尽可能降低特征的维度,即减小模型的大小。此时,我们使用L1正则化。
可以将 L2 的导数的作用理解为每次移除权重的 x%。如 Zeno 所知,对于任意数字,即使按每次减去 x% 的幅度执行数十亿次减法计算,最后得出的值也绝不会正好为 0。(Zeno 不太熟悉浮点精度限制,它可能会使结果正好为 0。)总而言之,L2 通常不会使权重变为 0。
可以将 L1 的导数的作用理解为每次从权重中减去一个常数。不过,由于减去的是绝对值,L1 在 0 处具有不连续性,这会导致与 0 相交的减法结果变为 0。例如,如果减法使权重从 +0.1 变为 -0.2,L1 便会将权重设为 0。就这样,L1 使权重变为 0 了。
L1 正则化 - 减少所有权重的绝对值 - 证明对宽度模型非常有效。