:特征工程
Posted Sonhhxg_柒
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了:特征工程相关的知识,希望对你有一定的参考价值。
🔎大家好,我是Sonhhxg_柒,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流🔎
📝个人主页-Sonhhxg_柒的博客_CSDN博客 📃
🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝
📣系列专栏 - 机器学习【ML】 自然语言处理【NLP】 深度学习【DL】
🖍foreword
✔说明⇢本人讲解主要包括Python、机器学习(ML)、深度学习(DL)、自然语言处理(NLP)等内容。
如果你对这个系列感兴趣的话,可以关注订阅哟👋
文章目录
2014 年,论文“Practical Lessons from Predicting Clicks on Ads at Facebook”声称,拥有正确的特征是开发他们的机器学习模型最重要的事情。从那时起,与我合作过的许多公司一次又一次地发现,与超参数调整等聪明的算法技术相比,一旦他们有了一个可行的模型,拥有正确的特性往往会给他们带来最大的性能提升。如果不使用一组好的特性,最先进的模型架构仍然会表现不佳。
由于其重要性,许多 ML 工程和数据科学工作的很大一部分是提出新的有用功能。在本章中,我们将讨论有关特征工程的常用技术和重要考虑因素。我们将专门用一节详细介绍一个微妙但灾难性的问题,该问题已使许多生产中的机器学习系统脱轨:数据泄漏以及如何检测和避免它。
我们将结束本章讨论如何设计好的特征,同时考虑特征重要性和特征泛化。说到特征工程,可能有人会想到特征存储。由于特征存储更接近于支持多个 ML 应用程序的基础设施,我们将在第 10 章介绍特征存储。
学习特征与工程特征
当我在课堂上讨论这个话题时,我的学生们经常问:“为什么我们要担心特征工程?难道深度学习不会向我们保证我们不再需要设计特征吗?”
他们是对的。深度学习的承诺是我们不必手工制作特征。因此,深度学习有时被称为特征学习。1许多特征可以通过算法自动学习和提取。然而,我们离所有功能都可以自动化的地步还很远。更不用说,在撰写本文时,生产中的大多数 ML 应用程序都不是深度学习。让我们通过一个示例来了解哪些特征可以自动提取,哪些特征仍然需要手工制作。
想象一下,您要构建情绪分析分类器,用于分类评论是否为垃圾邮件。在深度学习之前,当给定一段文本时,您必须手动应用经典的文本处理技术,例如词形还原、扩展收缩、删除标点符号和小写所有内容。之后,您可能希望将文本拆分为具有您选择的n 个值的 n-gram。
对于那些不熟悉的人,n-gram 是来自给定文本样本的n 个项目的连续序列。这项目可以是音素、音节、字母或单词。例如,给定帖子“我喜欢食物”,其单词级别的 1-gram 是 [“I”, “like”, “food”],其单词级别的 2-gram 是 [“I like”, “like食物”]。这句话的n-gram特征集,如果我们想让n为1和2,就是:[“I”,“like”,“food”,“I like”,“like food”]。
图 5-1显示了一个经典文本处理技术的示例,您可以使用这些技术为您的文本手工制作 n-gram 特征。
图 5-1。可用于为文本手工制作 n-gram 特征的技术示例
一旦你生成了 n-gram您的训练数据,您可以创建一个词汇表,将每个 n-gram 映射到一个索引。然后,您可以根据其 n-gram 索引将每个帖子转换为向量。例如,如果我们有一个包含 7 个 n-gram 的词汇表,如表 5-1所示,那么每个帖子都可以是一个包含七个元素的向量。每个元素对应于该索引处的 n-gram 在帖子中出现的次数。“我喜欢食物”将被编码为向量 [1, 1, 0, 1, 1, 0, 1]。然后可以将该向量用作 ML 模型的输入。
I | like | good | food | I like | good food | like food |
0 | 1 | 2 | 3 | 4 | 5 | 6 |
特征工程需要特定领域技术的知识——在这种情况下,领域是自然语言处理 (NLP) 和文本的母语。它往往是一个迭代过程,可能很脆弱。当我在一个早期的 NLP 项目中采用这种方法时,我一直不得不重新启动我的过程,要么是因为我忘记了应用一种技术,要么是因为我使用的一种技术效果不佳,我不得不撤消它。
然而,自从深度学习兴起以来,这种痛苦在很大程度上得到了缓解。不必担心词形还原、标点符号或停用词删除,您只需将原始文本拆分为单词(即标记化),从这些单词中创建词汇表,然后使用此方法将每个单词转换为一次性向量词汇。您的模型有望学会从中提取有用的特征。在这种新方法中,文本的大部分特征工程已经自动化。图像也取得了类似的进展。您无需手动从原始图像中提取特征并将这些特征输入到您的 ML 模型中,您只需将原始图像直接输入到您的深度学习模型中即可。
但是,ML 系统可能需要的数据不仅仅是文本和图像。例如,在检测评论是否为垃圾邮件时,除了评论本身的文本之外,您可能还想使用有关以下内容的其他信息:
评论
它有多少赞成票/反对票?
发表此评论的用户
此帐户是何时创建的,他们多久发布一次,以及他们有多少赞成/反对票?
发表评论的线程
它有多少视图?流行的线程往往会吸引更多的垃圾邮件。
在您的模型中可以使用许多可能的功能。其中一些如图 5-2所示。选择要使用的信息以及如何将此信息提取为 ML 模型可用的格式的过程是特征工程。对于复杂的任务,例如推荐视频供用户在 TikTok 上观看,使用的功能数量可能高达数百万。对于特定领域的任务,例如预测交易是否欺诈,您可能需要具备专业知识的银行和欺诈能够想出有用的功能。
图 5-2。模型中包含的关于评论、话题或用户的一些可能特征
通用特征工程操作
由于特征工程在 ML 项目中的重要性和普遍性,已经开发了许多技术来简化流程。在本节中,我们将讨论在从数据中设计特征时可能需要考虑的几个最重要的操作。它们包括处理缺失值、缩放、离散化、编码分类特征,以及生成老式但仍然非常有效的交叉特征以及更新和令人兴奋的位置特征。此列表远非全面,但它确实包含了一些最常见和最有用的操作,可以为您提供一个良好的起点。让我们潜入吧!
处理缺失值
您可能会注意到的第一件事在生产中处理数据时,缺少某些值。但是,我采访过的许多 ML 工程师不知道的一件事是,并非所有类型的缺失值都是相等的。2为了说明这一点,请考虑预测某人是否会在未来 12 个月内买房的任务。我们掌握的部分数据在表 5-2中。
ID | Age | Gender | Annual income | Marital status | Number of children | Job | Buy? |
---|---|---|---|---|---|---|---|
1 | A | 150,000 | 1 | Engineer | No | ||
2 | 27 | B | 50,000 | Teacher | No | ||
3 | A | 100,000 | Married | 2 | Yes | ||
4 | 40 | B | 2 | Engineer | Yes | ||
5 | 35 | B | Single | 0 | Doctor | Yes | |
6 | A | 50,000 | 0 | Teacher | No | ||
7 | 33 | B | 60,000 | Single | Teacher | No | |
8 | 20 | B | 10,000 | Student | No |
缺失值分为三种类型。这些类型的官方名称有点混乱,因此我们将通过详细的示例来减轻混淆。
非随机缺失 (MNAR)
这是缺少值的原因是因为真值本身。在这个例子中,我们可能会注意到一些受访者没有披露他们的收入。经调查发现,未报告的受访者的收入往往高于已披露的受访者。由于与值本身相关的原因,收入值缺失。
随机缺失 (MAR)
这是当一个值丢失的原因不是由于值本身,而是由于另一个观察到的变量。在在这个例子中,我们可能会注意到性别“A”的受访者经常缺少年龄值,这可能是因为本次调查中性别 A 的人不喜欢透露他们的年龄。
完全随机缺失 (MCAR)
这是当没有模式的时候缺少值。在这个例子中,我们可能认为“工作”列的缺失值可能是完全随机的,不是因为工作本身,也不是因为任何其他变量。人们有时会无缘无故忘记填写该值。然而,这种类型的失踪是非常罕见的。缺少某些值通常是有原因的,您应该进行调查。
遇到缺失值时,既可以用一定的值填充缺失值(插补),也可以去掉缺失值(删除)。我们将讨论两者。
删除
当我问候选人如何在面试过程中处理缺失值,许多人倾向于删除,不是因为它是一种更好的方法,而是因为它更容易做到。
删除的一种方法是删除列:如果一个变量有太多缺失值,只需删除它多变的。例如,在上面的示例中,变量“婚姻状况”的 50% 以上的值缺失,因此您可能想从模型中删除此变量。这种方法的缺点是您可能会删除重要信息并降低模型的准确性。婚姻状况可能与买房高度相关,因为已婚夫妇比单身人士更有可能成为房主。3
另一种删除方法是行删除:如果样本有缺失值,只需删除该样本。这种方法可以在缺失值完全随机(MCAR)且缺失值的示例数量较少(例如小于 0.1%)时起作用。如果这意味着删除了 10% 的数据样本,则您不想执行行删除。
但是,删除数据行也可能会删除模型进行预测所需的重要信息,尤其是在缺失值不是随机 (MNAR) 的情况下。例如,您不想删除收入缺失的性别 B 受访者样本,因为收入缺失的事实本身就是信息(收入缺失可能意味着更高的收入,因此与买房更相关)并且可以使用做出预测。
最重要的是,删除数据行可能会在模型中产生偏差,尤其是在缺失值是随机 (MAR) 的情况下。例如,如果您删除表 5-2中数据中所有缺失年龄值的示例,您将从数据中删除所有性别为 A 的受访者,您的模型将无法对性别为 A 的受访者做出良好的预测。
插补
即使删除很诱人,因为这很容易做到,删除数据会导致丢失重要信息并在模型中引入偏差。如果您不想删除缺失值,则必须估算它们,这意味着“用某些值填充它们”。决定使用哪些“特定值”是困难的部分。
一种常见的做法是用默认值填充缺失值。例如,如果作业丢失,您可以用空字符串“”填充它。另一种常见的做法是用平均值、中位数或众数(最常见的值)填充缺失值。例如,如果月份值为 7 月的数据样本缺少温度值,则使用 7 月的温度中值填充它不是一个坏主意。
这两种做法在许多情况下都很好用,但有时它们会导致毛毛虫。有一次,在我帮助的一个项目中,我们发现模型正在吐出垃圾,因为应用程序的前端不再要求用户输入他们的年龄,因此缺少年龄值,模型用 0 填充它们。但是该模型在训练期间从未看到年龄值为 0,因此无法做出合理的预测。
一般来说,要避免用可能的值来填充缺失值,例如用 0-0 填充缺失的子代数是子代数的可能值。这使得很难区分信息丢失的人和没有孩子的人。
可以同时或依次使用多种技术来处理特定数据集的缺失值。不管你使用什么技术,有一件事是肯定的:没有完美的方法来处理缺失值。删除后,您可能会丢失重要信息或加剧偏见。通过插补,您可能会注入自己的偏见向您的数据中添加噪音,或者更糟糕的是,数据泄漏。如果您不知道什么是数据泄漏,请不要惊慌,我们将在“数据泄漏”部分进行介绍。
缩放
考虑预测任务未来12个月是否有人买房,数据见表5-2。我们数据中变量 Age 的值范围为 20 到 40,而变量年收入的值范围为 10,000 到 150,000。当我们将这两个变量输入到 ML 模型中时,它不会理解 150,000 和 40 代表不同的事物。它只会将它们都视为数字,并且因为数字 150,000 比 40 大得多,它可能会赋予它更多的重要性,而不管哪个变量实际上对生成预测更有用。
在将特征输入模型之前,将它们缩放到相似的范围很重要。这个过程称为特征缩放。这是您可以做的最简单的事情之一,通常可以提高模型的性能。忽视这样做可能会导致您的模型做出胡言乱语的预测,尤其是使用梯度提升树和逻辑回归等经典算法时。4
扩展特征的一种直观方法是使它们在 [0, 1] 范围内。给定一个变量x,它的值可以使用以下公式重新调整到这个范围内:
您可以验证如果x是最大值,则缩放值x ' 将为 1。如果x是最小值,则缩放值x ' 将为 0。
如果您希望您的特征在任意范围 [ a , b ] 中——根据经验,我发现范围 [–1, 1] 比 [0, 1] 范围更好——你可以使用以下公式:
当您不想对变量做出任何假设时,缩放到任意范围效果很好。如果您认为您的变量可能服从正态分布,则将它们归一化以使它们具有零均值和单位方差可能会有所帮助。这个过程称为标准化:
和X¯是变量x的平均值,并且p是它的标准差。
在实践中,ML 模型倾向于与遵循偏态分布的功能作斗争。为了帮助减轻偏度,一种常用的技术是对数转换:将对数函数应用于您的特征。图 5-3显示了一个日志转换如何减少数据偏差的示例。虽然这种技术可以在许多情况下产生性能提升,但它并不适用于所有情况,您应该警惕对日志转换数据而不是原始数据执行的分析。5
图 5-3。在许多情况下,对数转换可以帮助减少数据的偏斜
关于缩放有两件重要的事情需要注意。一是它是数据泄漏的常见来源(这将在“数据泄漏”部分更详细地介绍)。另一个是它通常需要全局统计——你必须查看整个或一部分训练数据来计算它的最小值、最大值或平均值。在推理过程中,您可以重复使用在训练期间获得的统计数据来扩展新数据。如果新数据与训练相比发生了显着变化,那么这些统计数据将不是很有用。因此,经常重新训练您的模型以考虑到这一点很重要对于这些变化。
离散化
该技术包含在本书中,用于完整性,尽管在实践中,我很少发现离散化有帮助。假设我们已经使用表 5-2中的数据构建了一个模型。在训练过程中,我们的模型已经看到了“150,000”、“50,000”、“100,000”等的年收入值。在推理过程中,我们的模型遇到了一个年收入为“9,000.50”的例子。
直观地说,我们知道每年 9,000.50 美元与每年 10,000 美元没有太大区别,我们希望我们的模型以同样的方式对待这两者。但模型不知道这一点。我们的模型只知道 9,000.50 和 10,000 不同,它会区别对待它们。
离散化是将连续特征转化为离散特征的过程。这个过程也称为量化或分箱。这是通过为给定值创建存储桶来完成的。对于年收入,您可能希望将它们分为三个桶,如下所示:
-
较低的收入:低于 35,000 美元/年
-
中等收入:35,000 至 100,000 美元/年
-
高收入:超过10万美元/年
我们的模型不必学习无限数量的可能收入,而是可以只专注于学习三个类别,这是一项更容易学习的任务。这种技术应该对有限的训练数据更有帮助。
尽管根据定义,离散化是针对连续特征的,但它也可以用于离散特征。年龄变量是离散的,但将值分组到如下桶中可能仍然有用:
-
小于 18
-
18 至 22 岁之间
-
22 到 30 之间
-
30 到 40 之间
-
40 到 65 之间
-
65岁以上
缺点是这种分类在类别边界处引入了不连续性——34,999 美元现在被视为与 35,000 美元完全不同,后者被视为与 100,000 美元相同。选择类别的边界可能并不那么容易。你可以尝试绘制值的直方图并选择有意义的边界。一般来说,常识、基本分位数,有时甚至是主题专业知识都会有所帮助。
编码分类特征
我们已经讨论过如何转为连续特征转化为分类特征。在本节中,我们将讨论如何最好地处理分类特征。
没有在生产中使用过数据的人倾向于认为类别是静态的,这意味着类别不会随着时间而改变。许多类别都是如此。例如,年龄段和收入等级不太可能发生变化,并且您可以提前确切知道有多少类别。处理这些类别很简单。你可以给每个类别一个数字,你就完成了。
但是,在生产中,类别会发生变化。想象一下,您正在构建一个推荐系统来预测用户可能想从亚马逊购买哪些产品。您要使用的功能之一是产品品牌。在查看亚马逊的历史数据时,您会发现品牌众多。早在 2019 年,亚马逊上就已经有超过 200 万个品牌!6
品牌的数量是压倒性的,但你认为:“我仍然可以处理这个。” 您将每个品牌编码为一个数字,所以现在您有 200 万个数字,从 0 到 1,999,999,对应于 200 万个品牌。您的模型在历史测试集上表现出色,并且您获准在今天的 1% 的流量上对其进行测试。
在生产中,您的模型会崩溃,因为它遇到了以前从未见过的品牌,因此无法编码。新品牌一直在加入亚马逊。为了解决这个问题,您创建了一个值为 2,000,000 的类别 UNKNOWN,以捕获您的模型在训练期间未见过的所有品牌。
您的模型不再崩溃,但您的卖家抱怨他们的新品牌没有获得任何流量。这是因为您的模型在火车集中没有看到类别 UNKNOWN,所以它不推荐任何 UNKNOWN 品牌的产品。您可以通过仅将前 99% 最受欢迎的品牌编码并将后 1% 的品牌编码为 UNKNOWN 来解决此问题。这样,至少您的模型知道如何处理 UNKNOWN 品牌。
您的模型似乎可以正常工作大约一小时,然后产品推荐的点击率直线下降。在过去的一个小时内,有 20 个新品牌加入了您的网站;其中一些是新的奢侈品牌,其中一些是粗略的仿冒品牌,其中一些是老牌品牌。但是,您的模型对待它们的方式与处理训练数据中不受欢迎的品牌的方式相同。
这不是一个极端的例子,只有在亚马逊工作时才会发生。这个问题经常发生。例如,如果您想预测评论是否为垃圾邮件,您可能希望将发布此评论的帐户用作一项功能,并且一直在创建新帐户。新产品类型、新网站域、新餐厅、新公司、新 IP 地址等也是如此。如果你与他们中的任何一个一起工作,你将不得不处理这个问题。
找到解决这个问题的方法被证明是非常困难的。您不想将它们放入一组存储桶中,因为这真的很难——您甚至会如何将新用户帐户放入不同的组中?
这个问题的一种解决方案是散列技巧,由微软开发的包 Vowpal Wabbit 推广。7这个技巧的要点是您使用散列函数来生成每个类别的散列值。散列值将成为该类别的索引。因为可以指定散列空间,所以可以预先固定一个特征的编码值数量,而不必知道会有多少类别。例如,如果您选择一个 18 位的散列空间,对应于 2 18 = 262,144 个可能的散列值,那么所有类别,即使是您的模型从未见过的类别,都将由 0 到 262,143 之间的索引编码。
散列函数的一个问题是冲突:两个类别被分配了相同的索引。然而,对于许多散列函数,冲突是随机的;新品牌可以与任何现有品牌共享索引,而不是总是与不受欢迎的品牌共享索引,当我们使用前面的 UNKNOWN 类别时会发生这种情况。幸运的是,碰撞散列特征的影响并没有那么糟糕。在 Booking.com 的研究中,即使是 50% 的碰撞特征,性能损失也小于 0.5%,如图 5-4所示。8
图 5-4。50% 的碰撞率只会导致 log loss 增加不到 0.5%。资料来源:卢卡斯·伯纳迪
你可以选择一个足够大的散列空间来减少冲突。您还可以选择具有所需属性的散列函数,例如位置敏感的散列函数,其中相似的类别(例如具有相似名称的网站)被散列为彼此接近的值。
因为这是一个技巧,所以它经常被学者们认为是 hacky 并且被排除在 ML 课程之外。但它在行业中的广泛采用证明了该技巧的有效性。它对 Vowpal Wabbit 至关重要,它是 scikit-learn、TensorFlow 和 gensim 框架的一部分。它在模型的持续学习环境中特别有用从生产中的传入示例中学习。我们将在第 9 章介绍持续学习。
特征交叉
特征交叉是技术组合两个或多个特征以生成新特征。该技术可用于对特征之间的非线性关系进行建模。例如,对于预测某人是否会在未来 12 个月内买房的任务,您怀疑婚姻状况和孩子数量之间可能存在非线性关系,因此您将它们结合起来创建一个新特征“婚姻和儿童”,如表 5-3 所示。
表 5-3。如何组合两个功能以创建新功能的示例
Marriage | Single | Married | Single | Single | Married |
Children | 0 | 2 | 1 | 0 | 1 |
Marriage and children | Single, 0 | Married, 2 | Single, 1 | Single, 0 | Married, 1 |
因为特征交叉有助于对变量之间的非线性关系进行建模,所以对于无法学习或不善于学习非线性关系的模型(例如线性回归、逻辑回归和基于树的模型)来说,它是必不可少的。它在神经网络中不太重要,但它仍然很有用,因为显式特征交叉有时有助于神经网络更快地学习非线性关系。DeepFM 和 xDeepFM 是成功利用显式特征交互进行推荐系统和点击率预测的模型家族。9
特征交叉的一个警告是它可以让你的特征空间爆炸。假设特征 A 有 100 个可能的值,而特征 B 有 100 个可能的特征;交叉这两个特征将产生一个具有 100 × 100 = 10,000 个可能值的特征。您将需要更多的模型数据来学习所有这些可能的值。另一个需要注意的是,由于特征交叉增加了模型使用的特征数量,它会使模型过度拟合训练数据。
离散和连续位置嵌入
在论文“Attention Is All You Need” (Vaswani et al. 2017)中首次向深度学习社区介绍,位置嵌入已成为一种适用于计算机视觉和 NLP 中许多应用的标准数据工程技术。我们将通过一个示例来说明为什么位置嵌入是必要的以及如何做到这一点。
考虑语言建模任务,您希望根据先前的标记序列预测下一个标记(例如,单词、字符或子词)。在实践中,序列长度可以达到 512,如果不是更大的话。然而,为简单起见,让我们使用单词作为我们的标记,并使用 8 的序列长度。给定 8 个单词的任意序列,例如“有时我真正想做的是”,我们想要预测下一个单词。
嵌入
嵌入是一个向量代表一段数据。我们将由同一算法为一类数据生成的所有可能嵌入集合称为“嵌入空间”。同一空间中的所有嵌入向量具有相同的大小。
嵌入最常见的用途之一是词嵌入,您可以在其中用向量表示每个单词。然而,其他类型数据的嵌入越来越受欢迎。例如,Criteo 和 Coveo 等电子商务解决方案具有产品嵌入。10 Pinterest 嵌入了图像、图表、查询甚至用户。11鉴于嵌入的数据类型如此之多,人们对为多模态数据创建通用嵌入很感兴趣。
如果我们使用循环神经网络,它将按顺序处理单词,这意味着单词是隐式输入的。但是,如果我们使用像转换器这样的模型,单词是并行处理的,因此需要显式输入单词的位置,以便我们的模型知道这些单词的顺序(“a dog beats a child”与“a孩子咬狗”)。我们不想将绝对位置 0、1、2、...、7 输入到我们的模型中,因为根据经验,神经网络不能很好地处理非单位方差的输入(这就是我们缩放特征的原因,如前面“缩放”部分所述)。
如果我们将位置重新缩放到 0 和 1 之间,那么 0, 1, 2, ..., 7 变为 0, 0.143, 0.286, ..., 1,这两个位置之间的差异将太小,神经网络无法学习区分。
处理位置嵌入的一种方法是像对待词嵌入一样对待它。对于词嵌入,我们使用一个以词汇量大小作为列数的嵌入矩阵,每一列是该列索引处的词的嵌入。使用位置嵌入,列数就是位置数。在我们的例子中,因为我们只使用之前的序列大小 8,所以位置从 0 到 7(见图 5-5)。
以上是关于:特征工程的主要内容,如果未能解决你的问题,请参考以下文章