2018年11月26日星期一

ML_004:Google Machine Learning 在线速成课程学习笔记之四

在线课程地址:https://developers.google.com/machine-learning

7. 表示法

7.1 特征工程
传统编程的关注点是代码。在机器学习项目中,关注点变成了表示。也就是说,开发者通过添加和改善特征来调整模型。

将原始数据映射到特征
原始数据通过名为特征工程的程序映射到特征矢量。
上图左侧表示来自输入数据源的原始数据,右侧表示特征矢量,也就是组成数据集中样本的浮点值集。 特征工程指的是将原始数据转换为特征矢量。进行特征工程预计需要大量时间。

机器学习模型通常期望样本表示为实数矢量。这种矢量的构建方法如下:为每个字段衍生特征,然后将它们全部连接到一起。

映射数值
机器学习模型根据浮点值进行训练,因此整数和浮点原始数据不需要特殊编码。
将原始整数 (6) 映射到浮点特征 (6.0)。

映射字符串值
模型无法通过字符串值学习规律,因此您需要进行一些特征工程来将这些值转换为数字形式:

首先,为您要表示的所有特征的字符串值定义一个词汇表。对于 street_name 特征,该词汇表中将包含您知道的所有街道。
然后,使用该词汇表创建一个独热编码,用于将指定字符串值表示为二元矢量。在该矢量(与指定的字符串值对应)中:

  • 只有一个元素设为 1。
  • 其他所有元素均设为 0。
  • 该矢量的长度等于词汇表中的元素数。

通过独热编码映射字符串值。
上图显示了某条特定街道 (Shorebird Way) 的独热编码。在此二元矢量中,代表 Shorebird Way 的元素的值为 1,而代表所有其他街道的元素的值为 0。

映射分类(枚举)值
分类特征具有一组离散的可能值。例如,名为 Lowland Countries 的特征只包含 3 个可能值: {'Netherlands', 'Belgium', 'Luxembourg'}
您可能会将分类特征(如 Lowland Countries)编码为枚举类型或表示不同值的整数离散集。例如:
  • 将荷兰表示为 0
  • 将比利时表示为 1
  • 将卢森堡表示为 2
不过,机器学习模型通常将每个分类特征表示为单独的布尔值。例如,Lowland Countries 在模型中可以表示为 3 个单独的布尔值特征:
  • x1:是荷兰吗?
  • x2:是比利时吗?
  • x3:是卢森堡吗?
采用这种方法编码还可以简化某个值可能属于多个分类这种情况(例如,“与法国接壤”对于比利时和卢森堡来说都是 True)。

7.2 良好特征的特点

避免很少使用的离散特征值
良好的特征值应该在数据集中出现大约 5 次以上。这样一来,模型就可以学习该特征值与标签是如何关联的。也就是说,大量离散值相同的样本可让模型有机会了解不同设置中的特征,从而判断何时可以对标签很好地做出预测。
例如,house_type 特征可能包含大量样本,其中它的值为 victorian。
相反,如果某个特征的值仅出现一次或者很少出现,则模型就无法根据该特征进行预测。
例如,unique_house_id 就不适合作为特征,因为每个值只使用一次,模型无法从中学习任何规律。

最好具有清晰明确的含义
每个特征对于项目中的任何人来说都应该具有清晰明确的含义。

不要将“神奇”的值与实际数据混为一谈
良好的浮点特征不包含超出范围的异常断点或“神奇”的值。
例如,假设一个特征具有 0 到 1 之间的浮点值。那么,如下值是可以接受的:quality_rating: 0.37。
如果用户没有输入 quality_rating,则数据集可能使用如下神奇值来表示不存在该值:
quality_rating: -1。

为解决神奇值的问题,需将该特征转换为两个特征:

  • 一个特征只存储质量评分,不含神奇值。
  • 一个特征存储布尔值,表示是否提供了 quality_rating。为该布尔值特征指定一个名称,例如 is_quality_rating_defined。

考虑上游不稳定性
特征的定义不应随时间发生变化。例如,下列值是有用的,因为城市名称一般不会改变,example:city_id: "br/sao_paulo"
但收集由其他模型推理的值会产生额外成本。可能值“219”目前代表圣保罗,但这种表示在未来运行其他模型时可能轻易发生变化:inferred_city_cluster: "219"。

7.3 数据清理
作为一名机器学习工程师,您将花费大量的时间挑出坏样本并加工可以挽救的样本。即使是非常少量的“坏苹果”也会破坏掉一个大规模数据集。

缩放特征值
缩放是指将浮点特征值从自然范围(例如 100 到 900)转换为标准范围(例如 0 到 1 或 -1 到 +1)。如果某个特征集只包含一个特征,则缩放可以提供的实际好处微乎其微或根本没有。不过,如果特征集包含多个特征,则缩放特征可以带来以下优势:
  • 帮助梯度下降法更快速地收敛。
  • 帮助避免“NaN 陷阱”。在这种陷阱中,模型中的一个数值变成 NaN(例如,当某个值在训练期间超出浮点精确率限制时),并且模型中的所有其他数值最终也会因数学运算而变成 NaN。
  • 帮助模型为每个特征确定合适的权重。如果没有进行特征缩放,则模型会对范围较大的特征投入过多精力。
您不需要对每个浮点特征进行完全相同的缩放。即使特征 A 的范围是 -1 到 +1,同时特征 B 的范围是 -3 到 +3,也不会产生什么恶劣的影响。不过,如果特征 B 的范围是 5000 到 100000,您的模型会出现糟糕的响应。

处理极端离群值
如何最大限度降低这些极端离群值的影响?
一种方法是对每个值取对数。对数缩放可稍稍缓解这种影响,但仍然存在离群值这个大尾巴。
对此,我们采用另一种简单的方法:将某个特征的最大值“限制”为某个任意值,所有大于该值的值都将变为该值。

分箱
下图显示了加利福尼亚州不同纬度的房屋相对普及率。
每个纬度的房屋数曲线图。曲线图极其不规则,在纬度 36 左右出现低谷,并在纬度 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]
分箱之后,我们的模型现在可以为每个纬度学习完全不同的权重。

清查
截至目前,我们假定用于训练和测试的所有数据都是值得信赖的。在现实生活中,数据集中的很多样本是不可靠的,原因有以下一种或多种:
  • 遗漏值。 例如,有人忘记为某个房屋的年龄输入值。
  • 重复样本。 例如,服务器错误地将同一条记录上传了两次。
  • 不良标签。 例如,有人错误地将一颗橡树的图片标记为枫树。
  • 不良特征值。 例如,有人输入了多余的位数,或者温度计被遗落在太阳底下。
一旦检测到存在这些问题,您通常需要将相应样本从数据集中移除,从而“修正”不良样本。要检测遗漏值或重复样本,您可以编写一个简单的程序。检测不良特征值或标签可能会比较棘手。
除了检测各个不良样本之外,您还必须检测集合中的不良数据。直方图是一种用于可视化集合中数据的很好机制。此外,收集如下统计信息也会有所帮助:
  • 最大值和最小值
  • 均值和中间值
  • 标准偏差
考虑生成离散特征的最常见值列表。例如,country:uk 的样本数是否符合您的预期?language:jp 是否真的应该作为您数据集中的最常用语言?

了解数据
遵循以下规则:
  • 记住您预期的数据状态。
  • 确认数据是否满足这些预期(或者您可以解释为何数据不满足预期)。
  • 仔细检查训练数据是否与其他来源(例如信息中心)的数据一致。
像处理任何任务关键型代码一样谨慎处理您的数据。良好的机器学习依赖于良好的数据。