概述
特征工程的定义通常含糊不清,这通常会导致数据工作者感到困惑。 究竟什么是特征工程? 简而言之,特征工程是获取原始数据并为机器学习模型构建输入的过程。 实际上,这不仅仅是一个主题,而是许多技术汇集在一起,为用户形成了各种各样的实用带。我们认为特征工程的主要组成部分是:
- 特征创建
- 特征编码
- 特征提取
- 特征选择
- 预测工程
- 自动化特征工程
从历史上看,许多 ML 平台在区分这些任务方面做得不好。第 1 代 ML 平台和第 2 代 ML 平台的现状如下所示:
- 连接到源系统并从源系统中提取数据。
- 编写一堆 Python 代码来转换数据。
- 构建 ML 模型。
- 把notebook“越过篱笆”,让其他人操作。
特征工程的所有各个部分都包含在第 2 步中,理解它取决于读者解释代码的能力以及作者在代码中有效沟通的能力和愿望。结果类似于单个 DataFrame,它对于每个用例都是独一无二的,并带有一个独特的流水线。此外,每个用例的操作都有其自身的障碍,这些障碍不可避免地会使项目延迟并导致维护问题。当我们开始退后一步,将 ML 流程视为一个整体时,不难看出为什么如此多的公司难以通过第 1 代 ML 平台和第 2 代 ML 平台从 ML 中获取价值。
像 Continual 这样的数据优先的 ML 平台在第 3 代 ML 平台中呈上升趋势。第 3 代平台将数据置于 ML 工作流程的中心,并围绕它构建一个连贯的生产流程。如前所述,特征存储是第 3 代架构的关键组件,它是一项关键技术,使我们能够将特征工程分解为离散的部分,并围绕每个部分构建强大的自动化流程。如果没有特征平台(feature stores),很多这些都是不可能的。
下面,我们将更详细地探讨每个主题,特别关注如何在理想的第 3 代 ML 平台中处理每个主题。这些都是需要人工干预和编码的步骤吗?或者,我们能否从多年来培养的最佳实践中学习,并开始让用户在感兴趣时选择“快速路径”?作为一个搅局者,我们的论文是,一个设计良好的现代ML平台应该让用户专注于创建特征(通过特征创建)和目标(通过预测工程),其余的很步骤应该通过为高级用户提供的逃生舱口实现自动化。
特征创建
特征创建是从现有数据创建新特征的过程。这通常包括将数据连接在一起、创建窗口函数、跨组聚合数据等操作。这些都超出了特征表示的简单转换;也就是说,我们不是简单地以不同的方式看待现有数据,我们实际上是在创造新的东西。
例如,我可能有一个表,其中包含有关用户如何与我的网站交互的所有原始数据。我的首要任务之一可能是对这些数据进行会话化(sessionize),以便更好地了解用户在我们网站上完成的内容。 即,总共花费了多少时间,点击次数,向下滚动页面的百分比等。很容易挖掘这些数据并开始考虑构建有用的特征。当我开始构建 ML 模型时,我可能想要执行额外的操作,比如:总结连续三个月的用户参与度。在这个工作流程中,我明确地从现有数据中创建了许多新数据:这是特征创建。
在上面的示例中,我们可以将web事件转换为会话,并在会话的生命周期内构建特征,如:links_clicked
。
我的一位同事曾经开玩笑说“特征工程基本上是您的数据工程团队不想做的数据工程”。事实上,特征创建与数据工程非常相似。数据工程专注于将原始数据转换为分析和操作用例中的可用数据,数据工程和特征创建之间显然有许多相似之处。特征创建可以被视为数据工程师的“最后一英里”问题或数据科学家的“第一英里”问题,这模糊了两者之间的责任。尽管我们可能期望这种重叠是一个很好的协作机会,但最令人好奇的是,它在很大程度上表现为数据团队巨大的争论点。
在过去的几年里,你可能很幸运地听到了绞刑架上关于“数据科学家如何将 X% 以上的时间用于特征工程任务”的呼声。是的,很遗憾他们没有花更多的时间做数据科学,但这确实凸显了工作流程的错位。数据科学家主要使用 Python 工作,因为在第 1 代 ML 平台或第 2 代ML 平台工作流程中工作时,他们不可避免地必须使用 Python 来构建模型。因此,强迫他们使用 SQL 或 Java/Scala 只是为了让他们(数据科学家)与数据工程团队保持一致,然后在流程的下一步中转向 Python 并没有多大意义。由此产生的冲突是,数据科学团队最终会:执行自己的特征工程,重复数据工程团队的大量工作,也复制大量的数据,并维护自己的流水线。一段时间后,我们手上就有了一个真正的“流水线丛林”。同样,这些流水线很少是健壮的或易于生产化和维护的,因此, ML 用例将在这些约束下停滞不前。
这种冲突经常被错误地称为“SQL vs Python”的争论,但我们认为这两者只是无辜的旁观者,真正的罪魁祸首是采用机器学习平台,这在数据团队的不同部分之间造成了分歧。 第三代 ML 平台试图解决这个问题。特征平台正是解决这种冲突的东西:它充当一个抽象层,将特征的创建与特征的消费区分开来(以前在 Python 脚本中绑定在一起,而现在如何创建特征变得无关紧要),数据工程团队应该用大量数据来填充特征平台,当数据科学家有高级操作(operation)要注册(register)和共享时,他们也可以这样做。
下一步是将两个团队团结在一个共同的特征创建工具下。在 Continual 中,我们相信 dbt 可以成为那个工具。许多第 1 代 ML 平台和第 2 代 ML 平台不可避免地走上了构建自己的“数据整理(data wrangling)”功能的道路,并将其宣传为一个很棒的功能,但我们一直认为这实际上只会在数据团队中制造更多争吵。对于纯数据工程团队而言,这些工具通常不够健壮,缺乏 CI/CD 集成等功能,并且不可避免地无法提供真正的价值。 dbt 已经成为数据工程师的首选工具,并且是目前市场上最热门的开源工具之一。对于数据科学家来说,缺少的是快速连接到特征平台和 ML 工作流程,这正是 Continual 通过其 dbt 集成提供的功能。这就是我们的愿景:在一个共同的工作流程下联合数据团队。
将Continuous和dbt结合起来,可以在ML工作流程中提供全面的覆盖,如下图所示:
将 dbt 作为数据科学团队的主要特征创建工具的主要反对意见是,他们不希望仅限于“仅”使用 SQL。我们相信用户可能希望在 ML 工作流程中执行的许多 Python 式任务可以由精心设计的声明性系统处理,该系统将其从编码任务转变为配置决策——这是 Apple、Uber 和其他公司的团队所拥有的洞察力。但是,也有可能 dbt 并不一直有这个限制; dbt labs 首席执行官 Tristan Handy 最近的评论表明,我们可能会开始在 dbt 中看到非 SQL 支持。想象一下能够将 Pyspark 下推到 Databricks 或将纯 Python 下推到 Coiled 等。
当用户开始使用 Continual 时,他们会注意到 ML 工作流程的重点从模型构建、评估和跟踪转移到特征构建。我们认为这是用户应该花费大部分时间的地方。在这样做的过程中,公司积累了丰富的数据知识,可以快速应用于各种用例(场景)。在此之后,Continual 专注于自动化工作流程,并且在几分钟内构建和迭代模型非常容易。当我们开始与客户就他们的用例(场景)进行合作时,我们构建数十个模型来尝试不同的场景并在几分钟内完成的情况并不少见。我们认为这个工作流程对公司来说是一个巨大的解锁,并允许他们以创纪录的速度将 ML 应用到他们的公司中。
特征编码
特征编码是将原始特征转换为更适合模型构建的新特征的过程。如果这听起来类似于上面的特征创建,那么让我们指出主要区别在于我们没有在特征编码中添加任何新信息。相反,我们只是将特征的表示更改为 ML 算法更喜欢处理的东西。
例如,当我收集数据用作机器学习模型的输入时,不同的数值数据通常会有不同的尺度与它们相关联。也许我们有类似“帐户年龄”(一位数),“客户年龄”(两位数),“帐户余额”(从三位数到七位数),等等。通常的做法是对数值输入应用缩放和归一化,以便它们都映射到相同比例的值(通常是 (-1,1))。其他类型的编码可以与其他类型的输入一起发生。分类变量(Target)通常是散列(hashed)或独热(one-hot)编码。字符串通常被分词(tokenized)或索引等。为什么我们这样做超出了本文的范围,但可以说大多数 ML 算法都希望以这种方式提供输入。如果不这样做,模型可能会产生糟糕的结果。
我们使用一个超级简单的哈希函数对状态列进行编码,如下图所示:
特征编码在很大程度上是数据科学家的任务。这里有很多细微差别,不同的 ML 框架可能期望数据科学家在插入数据之前对数据做特定的事情。许多 ML 库有很多内置函数可以帮助做这些事情,但是,将正确的编码应用到正确的功能上,这是数据科学家的当务之急。
如果有人试图让他们的机器学习系统“民主化”,那么特征编码是他们将遇到的第一个障碍。我们不会期望非 DS 用户知道如何进行这些操作,也不会真正知道哪些框架期望使用哪些编码。但是,这是拥有 AutoML 框架非常有用的一个领域。一个好的 AutoML 框架会在将特征插入模型之前为用户执行所有必需的编码。鉴于 AutoML 框架可能与许多不同的算法和框架一起工作,确保正确完成编码是一项艰巨的任务,但这是一个巨大的附加值,也允许非 DS 进一步进入 ML 工作流程。
理想的第 3 代 ML 系统将根据用户的输入类型自动进行特征编码。平台开发人员应该能够了解将在实验阶段使用的算法需要哪些编码,并且应该根据提供的输入类型自动完成编码。对于高级用例(场景),可能还需要为用户提供逃生舱口以改变系统的行为。对于 Continual 的用户,编码是根据输入的特征类型自动选择的。类型是从底层数据仓库的数据类型自动推断出来的,但用户总是可以通过他们的特征集和模型定义来覆盖类型的关联。
特征提取
特征提取是用较少量的特征表示数据,同时仍保留数据集的核心信息的过程。这与降维密切相关,主要应用于文本、图像、视频和音频等复杂数据类型。流行的提取技术包括主成分分析、奇异值分解、Word2Vec、BERT、fastText 等;其中许多被称为嵌入(embeddings)或转换器(transformers)。
特征编码单独作用于每个特征值,而特征提取技术则作用于整个数据集,目的是降低数据集的复杂性,以便在后续 ML 模型中使用。嵌入和转换器通常是预先训练的,这意味着它们已经接受过特定任务的训练,例如:面部识别 (FaceNet) 或自然语言处理 (BERT)。然后,用户可以通过迁移学习在自己的 ML 流水线中利用这些预训练模型。这不仅是一个巨大的生产力收益,而且是一个很好的经济提升,因为许多预先训练的模型
重建起来并不便宜。