H2O 自动机器学习实践指南(全)
原文:
annas-archive.org/md5/598d72a11813e0f14a8bd7ffc3aed879
译者:飞龙
协议:CC BY-NC-SA 4.0
前言
随着互联网上产生的数据量巨大以及机器学习(ML)预测给企业带来的好处,ML 的实施已经成为一个低垂的果实,每个人都为之努力。然而,其背后的复杂数学可能会让很多用户感到沮丧。这就是 H2O 发挥作用的地方——它自动化了各种重复步骤,这种封装帮助开发者专注于结果而不是处理复杂性。
你将从理解 H2O 的 AutoML 如何通过提供一个简单、易于使用的界面来简化 ML 的实施开始。接下来,你将看到 AutoML 如何自动化训练多个模型、优化它们的超参数以及解释它们的性能。随着你的进步,你将了解到如何利用普通 Java 对象(POJO)和模型对象优化(MOJO)将你的模型部署到生产环境中。在这本书中,你将通过使用 H2O 的实际操作方法来学习,这将使你能够迅速设置你的 ML 系统。
在阅读完这本 H2O 书籍之后,你将能够使用 H2O AutoML 训练和使用你的 ML 模型,从实验到生产,无需理解复杂的统计学或数据科学。
这本书面向谁
这本书是为那些想要快速将 ML 融入他们的产品而无需担心训练 ML 模型内部复杂性的工程师和数据科学家而编写的。
如果你是一个想要将机器学习(ML)融入你的软件系统但不知道从何开始或在该领域没有太多专业知识的人,那么你会发现这本书很有用。
这本书涵盖的内容
第一章,理解 H2O AutoML 基础知识,介绍了 H2O.ai 的 AutoML 技术,并实现了一个基本的技术设置以观察其实际应用。
第二章,使用 H2O Flow(H2O 的 Web UI),探讨了 H2O 的 Web UI,称为 H2O Flow,并展示了我们如何使用 Web UI 设置我们的 H2O AutoML 系统,而无需编写任何代码。
第三章,理解数据处理,探讨了我们可以使用 H2O 内置的数据框操作执行的一些常见数据处理功能。
第四章,理解 H2O AutoML 训练和架构,深入探讨了 H2O 技术的高级架构,并教我们 H2O AutoML 如何训练所有模型并优化它们的超参数。
第五章,理解 AutoML 算法,探讨了 H2O AutoML 用于训练各种模型的多种机器学习算法。
第六章,理解 H2O AutoML 排行榜和其他性能指标,探讨了在 AutoML 排行榜中使用的不同性能指标,以及一些对用户来说很重要的附加指标。
第七章,使用模型可解释性,探讨了 H2O 可解释性界面,并帮助我们理解我们作为输出获得的各种可解释性功能。
第八章,探索 H2O AutoML 的可选参数,查看我们在配置 AutoML 训练时可用的一些可选参数,并展示如何使用它们。
第九章,探索 H2O AutoML 中的其他功能,探讨了 H2O AutoML 的两个独特功能。第一个是 H2O AutoML 与 scikit-learn 库的兼容性,第二个是 H2O AutoML 内置的日志系统,用于调试 AutoML 训练问题。
第十章,使用普通 Java 对象(POJOs),涵盖了模型 POJOs 以及我们如何提取和使用它们在生产环境中进行预测。
第十一章,使用模型对象,优化(MOJO),涵盖了模型 MOJOs,它们与模型 POJOs 的不同之处,如何查看它们,以及我们如何提取和使用它们在生产环境中进行预测。
第十二章,使用 H2O AutoML 和 Apache Spark,详细探讨了如何使用 H2O Sparkling Water 将 H2O AutoML 与 Apache Spark 结合使用。
第十三章,使用 H2O AutoML 与其他技术结合,探讨了如何将 H2O 模型与其他在机器学习领域常用的技术(如 Spring Boot Web 应用程序和 Apache Storm)协同使用。
为了充分利用本书
基本的统计学和编程知识有益。对机器学习和 Python 的一些了解将有所帮助。您需要在计算机上安装 Python,最好是 3.7 或更高版本,或者安装 R,版本为 4.0 或更高。所有代码示例都已使用 Windows 10 操作系统和 Ubuntu 22.04.1 LTS 上的 Python 3.10 和 R 4.1.2 进行测试。然而,它们也应该适用于未来的版本发布。
本书涵盖的软件/硬件 | 操作系统要求 |
---|---|
Python 3.10 | Windows、macOS 或 Linux |
R 4.1.2 | |
H2O 3.36.1.4 | |
Java 11 | |
Spark 3.2 | |
Scala 2.13 | |
Maven 3.8.6 |
如果您正在使用这本书的数字版,我们建议您亲自输入代码或访问 本书的 GitHub 代码库(下一节中提供了链接)。这样做将帮助您避免与代码复制和粘贴相关的任何潜在错误。
下载示例代码文件
您可以从 GitHub 下载本书的示例代码文件:github.com/PacktPublishing/Practical-Automated-Machine-Learning-on-H2O
。如果代码有更新,它将在 GitHub 仓库中更新。
我们还有其他来自我们丰富图书和视频目录的代码包,可在github.com/PacktPublishing/
找到。查看它们吧!
下载彩色图像
我们还提供了一份包含本书中使用的截图和图表彩色图像的 PDF 文件。您可以从这里下载:packt.link/IighZ
。
使用的约定
本书使用了多种文本约定。
文本中的代码
:表示文本中的代码单词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 昵称。以下是一个示例:“使用 POJO 模型唯一的依赖是h2o-genmodel.jar
文件。”
代码块设置如下:
import h2o
h2o.init()
当我们希望您注意代码块中的特定部分时,相关的行或项目将以粗体显示:
data_frame = h2o.import_file("Dataset/iris.data")
任何命令行输入或输出都按照以下方式编写:
mkdir H2O_POJO
cd H2O_POJO
粗体:表示新术语、重要单词或您在屏幕上看到的单词。例如,菜单或对话框中的单词以粗体显示。以下是一个示例:“您可以简单地点击下载 POJO按钮来下载模型作为 POJO。”
小贴士或重要提示
看起来是这样的。
联系我们
我们始终欢迎读者的反馈。
一般反馈:如果您对本书的任何方面有疑问,请通过customercare@packtpub.com给我们发邮件,并在邮件主题中提及书名。
勘误:尽管我们已经尽最大努力确保内容的准确性,但错误仍然可能发生。如果您在这本书中发现了错误,我们将不胜感激,如果您能向我们报告,我们将非常感谢。请访问www.packtpub.com/support/errata并填写表格。
盗版:如果您在互联网上以任何形式遇到我们作品的非法副本,我们将不胜感激,如果您能提供位置地址或网站名称,我们将非常感谢。请通过copyright@packt.com与我们联系,并提供材料的链接。
如果您有兴趣成为作者:如果您在某个领域有专业知识,并且您有兴趣撰写或为本书做出贡献,请访问authors.packtpub.com。
分享您的想法
一旦您阅读了《使用 H2O.ai 的实用自动化机器学习》,我们很乐意听到您的想法!请点击此处直接进入此书的亚马逊评论页面并分享您的反馈。
您的审阅对我们和科技社区都至关重要,并将帮助我们确保我们提供高质量的内容。
第一部分 H2O AutoML 基础
本部分的目标是帮助您实现一个简单、基础的演示,展示如何安装、设置和使用 H2O AutoML,从而进一步探索和实验这项技术。
本节包含以下章节:
-
第一章, 理解 H2O AutoML 基础
-
第二章, 使用 H2O 流 (H2O 的 Web UI)
第一章:理解 H2O AutoML 基础
机器学习(ML)是使用计算机系统构建分析或统计模型的过程,这些系统通过学习历史数据并从中识别模式。然后,这些系统使用这些模式并尝试做出预测性决策,这些决策可以为企业和研究提供价值。然而,实现一个能够提供任何具体价值的 ML 系统所需的复杂数学知识已经阻止了很多人尝试它,留下了大量他们本可以从中受益的未发现潜力。
自动化机器学习(AutoML)是最新 ML 技术之一,它加速了所有规模的组织对 ML 的采用。它是自动所有这些涉及 ML 生命周期复杂任务的过程。AutoML 将所有这些复杂性隐藏起来并在幕后自动化它们。这使得任何人都可以轻松实现 ML 而无需任何麻烦,并更多地关注结果。
本章,我们将学习 H2O.ai([www.h2o.ai/
](https://www.h2o.ai/))提供的一种 AutoML 技术,它简单地命名为 H2O AutoML。我们将提供 AutoML 的一般历史和它解决的问题的简要介绍,以及关于 H2O.ai 及其 H2O AutoML 技术的一些信息。然后,我们将使用 H2O 的 AutoML 技术编写一个简单的 ML 实现并构建我们的第一个 ML 模型。
到本章结束时,你将了解 AutoML 究竟是什么,H2O.ai 公司及其技术 H2O AutoML,以及使用 H2O AutoML 需要的最小要求。你还将了解如何使用 H2O AutoML 训练你的第一个 ML 模型,而无需理解任何复杂的数学火箭科学。
本章我们将涵盖以下主题:
-
理解 AutoML 和 H2O AutoML
-
使用 H2O AutoML 的最小系统要求
-
安装 Java
-
使用 Python 的 H2O 的基本实现
-
使用 R 的 H2O 的基本实现
-
使用 H2O AutoML 训练你的第一个 ML 模型
技术要求
对于本章,你需要以下内容:
-
一个不错的网络浏览器(Chrome、Firefox 或 Edge),你首选浏览器的最新版本。
-
你选择的 集成开发环境(IDE)
-
Project Jupyter 的 Jupyter Notebook (https://jupyter.org/)(可选)
本章的所有代码示例都可以在 GitHub 上找到,链接为 github.com/PacktPublishing/Practical-Automated-Machine-Learning-on-H2O/tree/main/Chapter%201
。
理解 AutoML 和 H2O AutoML
在我们开始使用 H2O AutoML 的旅程之前,了解 AutoML 究竟是什么以及它在整个机器学习(ML)流程中扮演什么角色是非常重要的。在本节中,我们将尝试理解 ML 流程中涉及的各个步骤以及 AutoML 如何融入其中。然后,我们将探讨是什么使得 H2O 的 AutoML 在众多 AutoML 技术中如此独特。
让我们先了解一下 AutoML 的一般概念。
AutoML
AutoML 是一个自动化过程,用于在开发用于预测的有效 ML 系统时执行的各种步骤。一个典型的 ML 流程包括以下步骤:
-
数据收集:这是 ML 流程中的第一步。数据从各种来源收集。这些来源可以生成不同类型的数据,如分类数据、数值数据、文本数据、时间序列数据,甚至视觉和听觉数据。所有这些类型的数据根据需求聚合在一起,并合并成一个共同的结构。这可能是一个逗号分隔值文件、一个 parquet 文件,甚至是一个数据库的表格。
-
数据探索:一旦收集到数据,就会使用基本的分析技术对其进行探索,以确定其包含的内容、数据的完整性和正确性,以及数据是否显示出可以构建模型的潜在模式。
-
数据准备:缺失值、重复数据和噪声数据都可能影响模型的质量,因为它们引入了错误的学习。因此,收集和探索的原始数据需要通过特定的数据处理方法进行预处理,以消除所有异常。
-
数据转换:许多 ML 模型可以处理不同类型的数据。一些可以处理分类数据,而另一些只能处理数值数据。这就是为什么你可能需要将某些类型的数据从一种形式转换为另一种形式。这允许在模型训练期间正确地提供数据集。
-
模型选择:一旦数据集准备就绪,就需要选择一个 ML 模型进行训练。模型的选择基于数据集包含的数据类型、需要从数据集中提取的信息以及哪种模型适合数据。
-
模型训练:这是模型被训练的地方。ML 系统将从处理后的数据集中学习并创建一个模型。这种训练可以受到多个因素的影响,例如数据属性加权、学习率和其他超参数。
-
超参数调整:除了模型训练之外,还需要考虑模型的架构。模型的架构取决于所使用的算法类型,例如随机森林中的树的数量或神经网络中的神经元数量。我们并不立即知道哪种架构对给定的模型是最优的,因此需要进行实验。定义模型架构的参数称为超参数;找到最佳的超参数值组合被称为超参数调整。
-
预测:机器学习管道的最终步骤是预测。基于模型在训练期间学习到的数据集模式,模型现在可以对未见数据做出一般化的预测。
对于非专业人士来说,所有这些步骤及其复杂性可能会令人感到压倒。机器学习管道过程中的每个步骤都是经过多年研究开发的,并且其中包含着广泛的主题。AutoML 是自动化这些步骤的大多数过程的过程,从数据探索到超参数调整,并提供最佳模型进行预测。这有助于公司专注于用结果解决现实世界问题,而不是机器学习过程和工作流程。
现在您已经了解了机器学习管道中的不同步骤以及这些步骤是如何被 AutoML 自动化的,让我们来看看为什么 H2O 的 AutoML 技术是行业领先技术之一。
H2O AutoML
H2O AutoML 是由 H2O.ai 开发的一种 AutoML 软件技术,通过提供用户友好的界面,帮助非专业人士进行机器学习实验,从而简化了机器学习系统的开发过程。它是一个内存中、分布式、快速且可扩展的机器学习和分析平台,适用于大数据,并且可以满足企业需求。
它是用 Java 编写的,并使用键值存储来访问数据、模型和其他涉及的机器学习对象。它运行在集群系统上,并使用多线程 MapReduce 框架来并行化数据操作。它还很容易与之通信,因为它使用简单的 REST API。最后,它有一个提供数据细节和模型详细信息的图形视图的网页界面。
H2O AutoML 不仅自动化了机器学习生命周期中涉及的大多数复杂步骤,还为即使是专家数据科学家实施专门的模型训练过程提供了很多灵活性。H2O AutoML 提供了一个简单的包装函数,封装了几个原本需要复杂编排的模型训练任务。它还拥有广泛的可解释性功能,可以描述模型训练生命周期的各种细节。这为用户提供易于导出的模型细节,用户可以使用这些细节来解释已训练模型的性能和合理性。
H2O AutoML 最好的部分是它是完全开源的。您可以在github.com/h2oai
找到 H2O 的源代码。它由一个在开源和闭源公司中服务的开发者社区积极维护。在撰写本文时,它处于第三个主要版本,这表明它是一个非常成熟的技术,并且功能丰富——也就是说,它支持世界上几家主要公司。它还支持包括 R、Scala、Python 和 Java 在内的多种编程语言,这些语言可以在多个操作系统上运行,并为涉及机器学习生命周期的各种数据源提供支持,例如 Hadoop 分布式文件系统、Hive、Amazon S3,甚至Java 数据库连接(JDBC)。
现在您已经了解了 AutoML 的基本知识以及 H2O AutoML 的强大功能,让我们看看系统运行 H2O AutoML 而不出现性能问题的最低要求。
使用 H2O AutoML 的最小系统要求
H2O 安装非常简单,但要确保它运行顺畅和高效,需要满足某些最低标准要求。以下是一些 H2O 在硬件能力方面所需的最低要求,以及其他软件支持:
-
H2O 所需的最小硬件如下:
-
内存:H2O 运行在内存架构上,因此它受限于使用它的系统的物理内存。因此,为了能够处理大量数据,系统拥有的内存越多越好。
-
中央处理器(CPU):默认情况下,H2O 将使用系统可用的最大 CPU 数量。然而,至少需要 4 个 CPU。
-
图形处理单元(GPU):如果 GPU 是 NVIDIA GPU(GPU Cloud,DGX Station,DGX-1 或 DGX-2)或 CUDA 8 GPU,则 AutoML 中的 XGBoost 模型才支持 GPU。
-
-
支持 H2O 的操作系统如下:
-
Ubuntu 12.04
-
OS X 10.9 或更高版本
-
Windows 7 或更高版本
-
CentOS 6 或更高版本
-
-
支持 H2O 的编程语言如下:
-
Java:Java 是 H2O 的强制要求。H2O 构建需要 64 位 JDK,运行其二进制文件需要 64 位 JRE:
- 支持的 Java 版本:Java SE 15,14,13,12,11,10,9 和 8
-
其他语言:以下语言仅在 H2O 在这些环境中运行时需要:
-
Python 2.7.x,3.5.x 或 3.6.x
-
Scala 2.10 或更高版本
-
R 版本 3 或更高版本
-
-
-
附加要求:以下要求仅在 H2O 在这些环境中运行时需要:
-
Hadoop:Cloudera CDH 5.4 或更高版本,Hortonworks HDP 2.2 或更高版本,MapR 4.0 或更高版本,或 IBM Open Platform 4.2
-
Conda:2.7,3.5 或 3.6
-
Spark:版本 2.1,2.2 或 2.3
-
一旦我们有一个满足最低要求的系统,我们需要关注 H2O 对其他软件的功能依赖。H2O 只有一个依赖项,那就是 Java。让我们看看为什么 Java 对 H2O 很重要,以及我们如何下载和安装正确的支持 Java 版本。
安装 Java
H2O 的核心代码是用 Java 编写的。它需要在你的系统中安装 Java 运行环境(JRE)来启动 H2O 服务器集群。H2O 还以多线程方式训练所有机器学习算法,这在其 MapReduce 框架之上使用了 Java Fork/Join 框架。因此,拥有与 H2O 兼容的最新 Java 版本以顺畅运行 H2O 非常推荐。
你可以从 www.oracle.com/java/technologies/downloads/
下载并安装最新稳定的 Java 版本。
在安装 Java 时,重要的是要知道你的系统运行的是哪种位版本。如果是 64 位版本,那么请确保你正在安装适用于你操作系统的 64 位 Java 版本。如果是 32 位,那么选择 32 位版本。
现在我们已经安装了正确的 Java 版本,我们可以下载并安装 H2O。让我们看看如何使用 Python 来完成这个简单的示例。
使用 Python 的 H2O 基本实现
Python 是计算机编程中机器学习(ML)领域最受欢迎的语言之一。它在所有行业中都得到广泛应用,并且拥有大量活跃维护的 ML 库,为创建 ML 管道提供了大量支持。
我们将首先安装 Python 编程语言,然后使用 Python 安装 H2O。
安装 Python
安装 Python 非常简单。无论是 Python 2.7 还是 Python 3 及以上版本,H2O 都可以与这两种语言版本完美兼容。然而,如果你使用的是 Python 2.7 以下的版本,那么你需要升级你的版本。
最好是使用 Python 3,因为它是当前的标准,Python 2.7 已经过时。除了 Python 之外,你还需要 pip
,Python 的包管理器。现在,让我们学习如何在各种操作系统上安装 Python:
-
在 Linux(Ubuntu、Mint、Debian)上:
-
对于 Python 2.7,请在系统终端中运行以下命令:
sudo apt-get python-pip
-
对于 Python 3,请在系统终端中运行以下命令:
sudo apt-get python3-pip
-
-
在 macOS 上:macOS 10.8 版本预装了 Python 2.7。如果你想安装 Python 3,请访问 https://python.org,进入 下载 部分,并下载适用于 macOS 的最新 Python 3 版本。
-
在 Windows 上:与 macOS 不同,Windows 没有预安装任何 Python 语言支持。你需要从
python.org
下载 Windows 的 Python 安装程序。安装程序将取决于你的 Windows 操作系统——也就是说,如果是 64 位还是 32 位。
现在你已经知道了如何安装正确的 Python 版本,让我们使用 Python 下载并安装 H2O Python 模块。
使用 Python 安装 H2O
H2O 在 Python 包索引中有一个 Python 模块可用。要安装h2o
Python 模块,您只需在您的终端中执行以下命令:
pip install h2o
就这么简单。
要测试是否已成功下载和安装,请按照以下步骤操作:
-
打开您的 Python 终端。
-
通过运行以下命令导入
h2o
模块:import h2o
-
通过运行以下命令初始化 H2O 以启动本地
h2o
服务器:h2o.init()
以下截图显示了初始化h2o
后应得到的结果:
图 1.1 – 使用 Python 执行 H2O
让我们快速查看我们得到的结果。首先,它运行成功,所以任务完成。
在通过读取输出日志执行h2o.init()
之后,您将看到 H2O 检查了是否在本地主机上的端口 54321 上已经有一个 H2O 服务器实例正在运行。在这种情况下,之前没有 H2O 服务器实例正在运行,所以 H2O 尝试在相同端口上启动本地服务器。如果它在该端口上找到了已经存在的本地 H2O 实例,那么它将重用该实例来执行任何进一步的 H2O 命令。
然后,它使用 Java 版本 16 启动了 H2O 实例。您可能看到不同的 Java 版本,这取决于您在系统中安装的版本。
接下来,您将看到服务器启动时使用的h2o jar
文件的位置,然后是Java 虚拟机(JVM)日志的位置。
一旦服务器启动并运行,它将显示在您系统上本地托管的 H2O 服务器 URL 以及 H2O Python 库与服务器连接的状态。
最后,您将看到一些关于服务器配置的基本元数据。这些元数据可能略不同于您在执行中看到的内容,因为它在很大程度上取决于您系统的规格。例如,默认情况下,H2O 将使用系统上可用的所有核心进行处理。所以,如果您有一个 8 核心的系统,那么H2O_cluster_allowed_cores
属性值将是8
。或者,如果您决定只使用四个核心,那么您可以执行h2o.init(nthreads=4)
来只使用四个核心,并在服务器配置输出中反映这一点。
现在您已经知道了如何使用 Python 实现 H2O,让我们学习如何在 R 编程语言中完成同样的操作。
使用 R 的基本 H2O 实现
R 编程语言在机器学习和数据科学领域非常受欢迎,因为它提供了广泛的统计和数据操作支持。数据科学家和数据挖掘者广泛使用它来开发分析软件。
我们将首先安装 R 编程语言,然后使用 R 安装 H2O。
安装 R
一支国际开发团队维护着 R 编程语言。他们为 R 编程语言设立了一个专门的网页,称为综合 R 存档网络(CRAN):cran.r-project.org/
. 根据你所使用的操作系统,安装 R 有不同的方法:
- 在 Linux(Ubuntu、Mint、Debian)上:
在系统终端中执行以下命令:
sudo apt-get install r-base
-
在 macOS 上:要安装 R,请访问
cran.r-project.org/
,点击下载 R for macOS超链接,并下载适用于 macOS 的最新 R 版本。 -
在 Windows 上:与你在 macOS 上安装 R 的方法类似,你可以从
cran.r-project.org/
下载.exe
文件,点击下载 R for Windows超链接,并下载适用于 Windows 的最新 R 版本。
在 macOS 和 Windows 上安装 R 的另一种好方法是使用 RStudio。RStudio 简化了 R 支持软件的安装,并且也是 R 编程的非常好用的 IDE。你可以从 www.rstudio.com/
下载 RStudio。
现在你已经知道了如何安装正确的 R 版本,让我们使用 R 编程语言下载并安装 H2O R 包。
使用 R 安装 H2O
与 Python 类似,H2O 也为 R 编程语言提供支持。
要安装 R 包,请按照以下步骤操作:
-
首先,我们需要下载 H2O R 包的依赖项。为此,在你的 R 终端中执行以下命令:
install.packages(c("RCurl", "jsonlite"))
-
然后,为了安装实际的
h2o
包,在你的 R 终端中执行以下命令:install.packages("h2o")
完成操作。
- 要测试是否已成功下载和安装,请打开你的 R 终端,导入
h2o
库,并执行h2o.init()
命令。这将启动一个本地的 H2O 服务器。
结果可以在以下屏幕截图中看到:
图 1.2 – 使用 R 执行 H2O
让我们快速查看我们得到的输出。
执行 h2o.init()
后,H2O 客户端将检查系统上是否已运行 H2O 服务器实例。H2O 服务器通常默认在端口 54321 上本地运行。如果它在该端口上找到了已存在的本地 H2O 实例,那么它将重用该实例。然而,在这个场景中,端口 54321 上没有运行任何 H2O 服务器实例,这就是为什么 H2O 尝试在相同端口上启动本地服务器的原因。
接下来,您将看到 JVM 日志的位置。一旦服务器启动并运行,H2O 客户端会尝试连接到它,并显示与服务器连接的状态。最后,您将看到一些关于服务器配置的基本元数据。这些元数据可能略不同于您在执行中看到的内容,因为它在很大程度上取决于您系统的规格。例如,默认情况下,H2O 将使用您系统上可用的所有核心进行处理。所以,如果您有一个 8 核心的系统,那么H2O_cluster_allowed_cores
属性值将是8
。或者,如果您决定只使用四个核心,则可以执行h2o.init(nthreads=4)
命令来只使用四个核心,从而在服务器配置输出中反映出来。
现在您已经知道了如何使用 Python 和 R 实现 H2O,让我们创建我们的第一个机器学习模型,并使用 H2O AutoML 对其做出预测。
使用 H2O AutoML 训练您的第一个机器学习模型
所有机器学习管道,无论它们是否自动化,最终都遵循本章中“理解 AutoML 和 H2O AutoML”部分讨论的相同步骤。
对于这个实现,我们将使用鸢尾花数据集。这个数据集可以在archive.ics.uci.edu/ml/datasets/iris
找到。
理解鸢尾花数据集
鸢尾花数据集,也称为费舍尔的鸢尾花数据集,是最受欢迎的多变量数据集之一——也就是说,这是一个在模型训练过程中每个观测值分析两个或更多变量的数据集。该数据集包括三种不同品种的鸢尾花样本 50 个。数据集中的特征包括花瓣和萼片的长度和宽度(以厘米为单位)。由于其简单性,该数据集常用于研究机器学习中的各种分类技术。分类是通过使用花瓣和萼片的长度和宽度作为特征来确定的,这些特征决定了鸢尾花的类别。
以下截图显示了数据集的一个小样本:
图 1.3 – 鸢尾花数据集
数据集中的列代表以下内容:
-
C1:萼片长度(厘米)
-
C2:萼片宽度(厘米)
-
C3:花瓣长度(厘米)
-
C4:花瓣宽度(厘米)
-
C5:类别:
-
Iris-setosa
-
Iris-versicolour
-
Iris-virginica
-
在这个场景中,C1、C2、C3 和 C4 代表用于确定C5(即鸢尾花类别)的特征。
现在您已经理解了我们将要处理的数据集的内容,让我们实现我们的模型训练代码。
模型训练
模型训练 是寻找给定机器学习算法的最佳偏差和权重组合的过程,以便它最小化损失函数。损失函数 是衡量预测值与实际值之间距离的一种方法。因此,最小化它表示模型正在接近做出准确的预测——换句话说,它正在学习。机器学习算法构建了数据集中各种特征与目标标签之间关系的数学表示。然后,我们使用这种数学表示来预测目标标签对于某些特征值的潜在值。预测值的准确性很大程度上取决于数据集的质量,以及模型训练期间使用的权重和偏差与特征的组合。然而,所有这些都可以由 AutoML 完全自动化,因此对我们来说不是问题。
考虑到这一点,让我们学习如何快速简单地使用 H2O 在 Python 中创建一个机器学习模型。
Python 中的模型训练和预测
H2O Python 模块使得在 Python 程序中使用 H2O 变得容易。H2O Python 模块中的内置函数易于使用,并隐藏了使用 H2O 的许多复杂性。
按照以下步骤在 Python 中使用 H2O AutoML 训练您的第一个模型:
-
导入 H2O 模块:
import h2o
-
初始化 H2O 以启动本地 H2O 服务器:
h2o.init()
h2o.init()
命令启动或重用本地端口 54321 上运行的 H2O 服务器实例。
-
现在,您可以使用
h2o.import_file()
命令导入数据集,同时将数据集在系统中的位置传递进去。 -
接下来,通过传递数据集下载位置来导入数据集:
data = h2o.import_file("Dataset/iris.data")
-
现在,您需要确定 DataFrame 的哪些列是特征,哪些是标签。
C1
、C2
、C3
、C4
和C5
作为特征列表:features = data.columns
-
根据我们的 DataFrame,表示 Iris 花类的
C5
列是我们希望在模型训练后最终预测的列。因此,我们将C5
标记为标签,并从剩余的列名集合中删除它,我们将这些列标记为特征。设置目标标签并从特征列表中删除:label = "C5" features.remove(label)
-
将 DataFrame 分割为训练和测试 DataFrame:
train_dataframe, test_dataframe = data.split_frame([0.8])
data.split_frame([0.8])
命令将 DataFrame 分割成两个——一个训练 DataFrame 和另一个用于测试的 DataFrame。训练 DataFrame 包含 80% 的数据,而测试 DataFrame 包含剩余的 20%。我们将使用训练 DataFrame 来训练模型,并在模型训练后使用测试 DataFrame 来运行预测,以测试模型的性能。
小贴士
如果你对 H2O 如何根据比例分割数据集以及如何在不同分割之间随机化数据感兴趣,请随意探索并使用 split_frame
函数进行实验。更多详细信息请参阅 https://docs.h2o.ai/h2o/latest-stable/h2o-py/docs/_modules/h2o/frame.xhtml#H2OFrame.split_frame。
-
初始化 H2O AutoML 对象。在这里,我们将
max_model
参数设置为10
以限制 H2O 将训练的模型数量,将 AutoML 设置为10
,并将随机seed
生成器设置为1
:aml=h2o.automl.H2OAutoML(max_models=10, seed = 1)
-
现在,通过传递特征列 – 即
C1
、C2
、C3
和C4
– 在 (x) 中,标签列C5
在 (y) 中,以及使用aml.train()
命令的train_dataframe
DataFrame 来触发 AutoML 训练。这是 H2O 开始其自动模型训练的时候。 -
使用 H2O AutoML 对象训练模型:
aml.train(x = features, y = label, training_frame = train_dataframe)
在训练过程中,H2O 将分析标签列的类型。对于数值标签,H2O 将机器学习问题视为回归问题。如果标签是分类的,那么它将问题视为分类问题。对于 Iris 花数据集,C5
列包含类值的分类值。H2O 将分析此列并正确识别它是一个分类问题,并训练分类模型。
H2O AutoML 在幕后使用不同类型的机器学习算法训练多个模型。所有已训练的模型都在测试数据集上评估,并测量其性能。H2O 还提供了有关所有模型的详细信息,用户可以使用这些信息进一步对数据进行实验或比较不同的机器学习算法,了解哪些更适合解决他们的机器学习问题。H2O 最终可能训练 20-30 个模型,这可能需要一段时间。然而,由于我们已将 max_models
参数设置为 10
,因此我们限制了将被训练的模型数量,以便我们可以快速查看训练过程的输出。关于集成学习的更多内容将在 第五章,理解 AutoML 算法 中讨论。
-
一旦训练完成,AutoML 将创建一个包含它所训练的所有模型的领航表,从表现最好的到最差的进行排名。这个排名是通过比较所有模型的错误度量来实现的。错误度量是衡量模型在预测样本测试数据集时犯错误数量的值。较低的错误度量表示模型在预测过程中犯的错误较少,这表明与错误度量较高的模型相比,它是一个更好的模型。提取 AutoML 领航表:
model_leaderboard = aml.leaderboard
-
显示 AutoML 领航表:
model_leaderboard.head(rows=model_leaderboard.nrows)
领航表将如下所示:
图 1.4 – H2O AutoML 领航表(Python)
领航表包括以下详细信息:
-
model_id
:这代表模型的 ID。 -
mean_per_class_error
:此度量用于衡量多类数据集中每个类错误的平均值。 -
logloss
:此度量用于衡量每个实例校正预测概率对数的负平均值。 -
均方根误差(RMSE):此度量用于衡量预测误差的标准差。
-
均方误差(MSE):此指标用于衡量误差平方的平均值。
根据 ML 问题的类型,排行榜会根据某些默认指标对模型进行排序,除非在 AutoML 训练期间有特别说明。对于多项式分类,排行榜会根据mean_per_class_error
排序,而对于回归则是偏差。
指标是模型性能中误差的不同度量。因此,误差值越小,模型在做出准确预测方面的表现越好。我们将在第六章中探讨不同的模型性能指标,理解 H2O AutoML 排行榜和其他性能指标。
在这种情况下,GLM_1_AutoML_1_20211221_224844
是 H2O AutoML 认为的最佳模型,因为它是一个多项式分类问题,并且这个模型的mean_per_class_error
最低。
您可能会注意到,尽管将max_model
值设置为10
,但在触发 AutoML 进行训练时,我们在排行榜上看到超过 10 个模型。这是因为只有 10 个模型被训练;其余的模型是 Stacked Ensemble 模型。Stacked Ensemble模型是由其他模型学习到的内容创建的模型,并且从技术上讲并不是以正常方式训练的。我们将在第五章中了解更多关于 Stacked Ensemble 模型的信息,以及在第六章中了解更多关于排行榜的信息,理解 H2O AutoML 排行榜和其他性能指标。
恭喜!您已正式使用 H2O AutoML 训练了您的第一个 ML 模型,现在它可以用于做出预测。
做出预测非常简单:我们将使用由data.split_frame([0.8])
命令创建的test_dataframe
DataFrame。
在 Python 中执行以下命令:
aml.predict(test_dataframe)
就这样——一切都在模型对象的predict
函数中封装。
执行预测后,您将看到以下结果:
图 1.5 – H2O AutoML 模型预测(Python)
预测结果显示一个表格,其中每一行都是测试 DataFrame 中现有行的预测表示。predict
列指示该行属于哪种 Iris 类别,而其余列是模型在读取该行的特征值后计算出的 Iris 类别的概率,如列名所示。简而言之,模型预测对于行 1,有99.6763%的概率是 Iris-setosa。
恭喜!您现在已使用 AutoML 训练的新模型做出了准确的预测。
现在我们已经看到了在 Python 中使用 H2O AutoML 是多么简单,让我们学习如何在 R 编程语言中做到同样的事情。
R 中的模型训练和预测
与 Python 类似,在 R 编程语言中使用 H2O AutoML 进行训练和预测也非常简单。H2O 对 R 编程语言有很多支持,因此它将许多 ML 的复杂性封装在可用的函数中。
让我们看看一个使用 R 编程语言在 Iris 花数据集上使用 H2O AutoML 进行模型训练的示例。
你会注意到在 R 中训练模型的方式与我们在 Python 中做的方式相似,唯一的区别是语法上的细微变化。
按照以下步骤操作:
-
导入
H2O
库:library(h2o)
-
初始化 H2O 以启动本地 H2O 服务器:
h2o.init()
h2o.init()
将启动一个运行在本地的端口 54321 上的 H2O 服务器实例,并将其连接。如果同一端口上已经存在 H2O 服务器,则将重用它。
-
使用
h2o.importFile(“Dataset/iris.data”)
导入数据集,同时将数据集在系统中的位置作为参数传递。导入数据集:data <- h2o.importFile("Dataset/iris.data")
-
现在,你需要设置数据框的哪些列是特征,哪些列是标签。将
C5
列设置为目标标签,其余列名作为特征列表:label <- "C5" features <- setdiff(names(data), label)
-
将 DataFrame 分为两部分:
parts <- h2o.splitFrame(data, 0.8)
将使用一个 DataFrame 进行训练,而另一个将用于测试/验证正在训练的模型。parts <- h2o.splitFrame(data, 0.8)
将 DataFrame 分为两部分。一个 DataFrame 包含 80%的数据,而另一个包含剩余的 20%。现在,将包含 80%数据的 DataFrame 指定为训练 DataFrame,另一个指定为测试或验证 DataFrame。
-
将第一部分指定为训练 DataFrame:
train_dataframe <- parts[[1]]
-
将第二部分指定为测试 DataFrame:
test_dataframe <- parts[[2]]
-
现在数据集已经导入,其特征和标签也已识别,让我们将它们传递给 H2O 的 AutoML 以训练模型。这意味着你可以在 R 中使用
h2o.automl()
函数实现 AutoML 模型训练功能。使用 H2O AutoML 训练模型:aml <- h2o.automl(x = features, y = label, training_frame = train_dataframe, max_models=10, seed = 1)
-
提取 AutoML 排行榜:
model_leaderboard <- aml@leaderboard
-
显示 AutoML 排行榜:
print(model_leaderboard, n = nrow(model_leaderboard))
一旦训练完成,AutoML 将创建一个排行榜,列出它所训练的所有模型,从表现最好的到最差的进行排名。
排行榜将按以下方式显示结果:
图 1.6 – H2O AutoML 排行榜(R)
排行榜包括我们在 Python 中训练模型时看到的排行榜上的相同详细信息。
然而,你可能注意到这个排行榜中建议的最佳模型与我们之前的实验中得到的模型不同。
在这种情况下,GBM_3_AutoML_8_20211222_02555
是 H2O AutoML 认定的最佳模型,而在之前的实验中,它是 GLM_1_AutoML_1_20211221_224844
。这可能是由于几个因素造成的,例如在模型训练过程中种子值生成了不同的随机数,或者两个实验之间在训练和测试 DataFrame 中分割的数据值不同。这就是机器学习复杂的地方——你在模型训练流程中执行的每一步都可能极大地影响你训练的模型的整体性能。最终,机器学习是一种力求做出最准确预测的最佳努力方法。
恭喜你 – 你已经正式使用 R 中的 H2O AutoML 训练了你的机器学习模型。现在,让我们学习如何对其做出预测。我们将使用在分割函数之后创建的测试 DataFrame 对我们训练的模型进行预测。
在 R 中执行以下命令进行预测:
predictions <- h2o.predict(aml, test_dataframe)
h2o
对象的 predict
函数接受两个参数。一个是模型对象,在我们的例子中是 aml
对象,另一个是要进行预测的 DataFrame。默认情况下,aml
对象将使用排行榜中的最佳模型进行预测。
执行预测后,你将看到以下结果:
图 1.7 – H2O AutoML 模型预测(R)
结果显示一个表格,其中包含与我们之前用 Python 进行的实验中看到类似的详细信息。每一行都是测试 DataFrame 中现有行的预测表示。predict
列指示该行的 Iris 类别,而其余列是 Iris 类别的计算概率。
恭喜你 – 你已经使用 R 中的 AutoML 新训练的模型做出了准确的预测。现在,让我们总结本章内容。
摘要
在本章中,我们了解了机器学习流程中的各个步骤以及 AutoML 如何在自动化这些步骤中发挥作用。然后,我们通过安装基本需求来准备我们的系统以使用 H2O AutoML。一旦我们的系统准备就绪,我们就在 Python 和 R 中实现了一个简单的应用程序,该程序使用 H2O AutoML 在 Iris 花数据集上训练模型。最后,我们了解了排行榜结果,并对我们刚刚训练的机器学习模型进行了成功的预测。所有这些都帮助我们测试了 H2O AutoML 的水,从而打开了通往 H2O AutoML 更高级概念的门户。
在下一章中,我们将探索 H2O 的 Web 用户界面(UI),以便我们可以通过交互式可视化界面理解和观察各种机器学习细节。
第二章:在 H2O Flow(H2O 的 Web UI)中工作
机器学习(ML)不仅仅是代码。它涉及从不同角度的大量观察。尽管实际编码非常强大,但很多信息都隐藏在编码的终端后面。人类总是比文字更容易理解图片。同样,ML 虽然复杂,但在交互式用户界面(UI)的帮助下,可以非常容易且有趣地实现。在学习困难主题时,在单调的黑白像素化终端上使用彩色的 UI 总是加分。
H2O Flow是由 H2O.ai 团队开发的一个基于 Web 的 UI。这个界面运行在我们已经在第一章的理解 H2O AutoML 基础部分中了解到的相同后端。它只是将主 H2O 库包装成一个 Web UI,在后端服务器上传递输入并触发函数,并通过将结果显示给用户来读取结果。
在本章中,我们将学习如何使用 H2O Flow。我们将执行 ML 管道的所有典型步骤,这些步骤我们在第一章的理解 AutoML 和 H2O AutoML部分中已经了解,即理解 H2O AutoML 基础,从读取数据集到使用训练好的模型进行预测。此外,我们还将探索一些指标和模型细节,以帮助我们更容易地进入更高级的主题。本章是实践性的,我们将在创建我们的 ML 管道时了解 H2O Flow 的各个部分。
到本章结束时,你将能够导航和使用 H2O Flow 的各种功能。此外,你将能够使用 H2O Flow 训练你的 ML 模型,并用于预测,而无需编写任何代码。
在本章中,我们将涵盖以下主题:
-
理解 H2O Flow 的基础
-
在 H2O Flow 中处理数据函数
-
在 H2O Flow 中处理模型训练函数
-
在 H2O Flow 中处理预测函数
技术要求
你将需要以下内容:
- 一个不错的 Web 浏览器(Chrome、Firefox 或 Edge),你首选 Web 浏览器的最新版本。
理解 H2O Flow 的基础
H2O Flow 是一个开源的 Web 界面,它帮助用户在单个称为Flow 笔记本或简称Flow的页面上执行代码、绘制图表和显示数据框。
Jupyter 笔记本的用户会发现 H2O Flow 非常相似。你可以在单元格中编写可执行代码,当你执行单元格时,代码的输出会显示在其下方。然后,光标会移动到下一个单元格。Flow 最好的地方在于它可以很容易地保存、导出和导入到各种用户之间。这有助于许多数据科学家在各个利益相关者之间共享结果,因为他们只需保存执行结果并分享流程。
在以下子节中,我们将了解 H2O Flow 的基础知识。让我们从下载 H2O Flow 到我们的系统开始我们的 H2O Flow 之旅。
下载和启动 H2O Flow
为了运行 H2O Flow,您需要首先将 H2O Flow 的 Java 归档(JAR)文件下载到您的系统上,然后下载完成后运行该 JAR 文件。
您可以使用以下步骤下载并启动 H2O Flow:
-
您可以从
h2o-release.s3.amazonaws.com/h2o/master/latest.xhtml
下载 H2O Flow。 -
一旦 ZIP 文件下载完成,打开终端,在下载 ZIP 文件的文件夹中运行以下命令:
unzip {name_of_the_h2o_zip_file}
-
要运行 H2O Flow,请在解压缩后的
h2o
文件夹内运行以下命令:java -jar h2o.jar
这将在 localhost:54321
上启动 H2O Web UI。
现在我们已经下载并启动了 H2O Flow,让我们简要地探索它,以了解它提供的功能。
探索 H2O Flow
H2O Flow 是一个非常功能丰富的应用程序。它几乎拥有您创建机器学习(ML)管道所需的所有功能。考虑到机器学习(ML)管道中涉及的各个步骤,H2O Flow 为这些步骤提供了丰富的功能。这对很多人来说可能会感到不知所措。因此,探索应用程序并一次关注应用程序的特定部分是非常有价值的。
在以下章节中,我们将详细了解这些部分;然而,一些功能可能在这个阶段过于复杂,难以理解。我们将在接下来的章节中更好地理解它们。目前,我们将专注于了解如何使用 H2O Flow 创建我们的机器学习(ML)管道。
因此,让我们首先通过启动 H2O Flow 并在 localhost:54321
URL 打开您的网络浏览器来进行探索。
以下截图显示了 H2O Flow UI 的主页面:
图 2.1 – H2O Flow UI 的主页面
如果您看到一些细微的差异,请不要惊慌。这可能是由于您安装的版本可能与本书中显示的不同。尽管如此,UI 的基本设置应该是相似的。正如您所看到的,有大量的交互式选项可供选择。一开始可能会有些令人不知所措,所以让我们一步一步来。
在网页的顶部,有各种机器学习对象操作,每个操作都有自己的功能下拉列表。它们如下所示:
-
Flow:本节包含所有与 Flow 笔记本相关的操作。
-
Cell:本节包含所有与笔记本中单个单元格相关的操作。
-
Data:本节包含所有与数据处理相关的操作。
-
Model:本节包含所有与模型训练和算法相关的操作。
-
评分: 这个部分包含所有与评分和预测相关的操作。
-
管理员: 这个部分包含所有管理操作,例如下载日志。
-
帮助: 这个部分包含所有指向 H2O 文档的链接,以获取更多详细信息。
一旦我们开始创建我们的机器学习管道,我们将逐步详细地介绍它们。
以下截图显示了 H2O Flow UI 的各种机器学习功能操作:
图 2.2 – 机器学习对象操作工具栏
在此之后,我们有流名称和流工具栏设置。默认情况下,流名称将是未命名流程。流名称有助于在一般情况下识别整个流程,这样你就不会混淆不同的实验。流工具栏部分是一个简单的工具栏,它帮助你进行基本操作,例如编辑和管理你流程中的单元格。
以下截图显示了主页上存在的流程工具栏:
图 2.3 – 流名称和流工具栏部分
单元格是你可以逐个执行的代码执行行。它们也可以用来添加注释、标题,甚至是 Markdown 文本。
工具列表如下。我们将从左到右开始:
-
新建: 这将创建一个新的 Flow 笔记本。
-
打开: 这将打开存储在你系统中的现有 Flow 笔记本。
-
保存: 这将保存你的当前流程。
-
插入单元格: 这将在下方插入一个单元格。
-
向上移动: 这会将当前高亮的单元格向上移动到上面的单元格之上。
-
向下移动: 这将当前高亮的单元格移动到其下的单元格下方。
-
剪切: 这将剪切单元格并将其存储在剪贴板上。
-
复制: 这将复制当前高亮的单元格。
-
粘贴: 这将在当前高亮的单元格下方粘贴之前复制的单元格。
-
清除单元格: 如果有输出,这将清除单元格的输出。
-
删除单元格: 这将完全删除单元格。
-
运行并选择下方: 这将运行当前高亮的单元格,并在下面的单元格处停止。
-
运行: 这将运行当前高亮的单元格。
-
运行所有: 这将逐个从上到下运行所有单元格。
-
协助我: 这将执行一个协助命令,通过显示基本机器学习命令的链接来帮助你。
在你的流程的右侧有额外的支持选项,帮助你管理你的工作流程。你有概要、流程、剪辑和帮助。每个选项都有自己的列,包含功能细节。
以下截图显示了 H2O Flow UI 的各种支持选项:
图 2.4 – 支持选项
概述列显示了您执行的所有操作的列表。查看概述可以帮助您快速检查在创建您的机器学习管道时执行的步骤是否按正确顺序排列,是否有任何重复,或者是否有任何错误的步骤。
以下截图显示了概述支持选项部分:
图 2.5 – 概述
流程列显示了您之前保存的所有流程。目前,您不会有任何,但一旦您保存了流程,它将在这里显示,并提供快速链接以打开它。请注意,在 H2O Flow 页面上一次只能打开一个 Flow 笔记本。如果您想同时处理多个流程,可以通过打开另一个标签页并在那里打开 Flow 笔记本来实现。
以下截图显示了流程支持选项部分:
图 2.6 – 保存的流程
CLIPS列是您的剪贴板。如果您在流程中要多次运行的任何代码,则可以一次性编写并保存到剪贴板,方法是选择单元格右侧的纸夹图标。然后,您可以在需要时粘贴该单元格,而无需在流程中搜索它。剪贴板还存储了一定数量的垃圾单元格。
以下截图显示了CLIPS支持选项部分:
图 2.7 – 剪贴板
帮助列显示了各种资源,以帮助用户使用 H2O Flow。这包括快速入门视频、示例流程、一般使用示例以及指向官方文档的链接。请随意探索这些资源,以了解您如何使用 H2O Flow。
以下截图显示了帮助支持选项部分:
图 2.8 – 帮助部分
返回页面顶部,让我们探索前两个下拉列表。它们足够简单,易于理解。
以下截图显示了操作的第一下拉列表,即流程对象操作:
图 2.9 – 流程函数下拉列表
流程操作的下拉列表在一般意义上具有基本功能。您可以创建新的流程、打开现有的流程、保存、复制、运行流程中的所有单元格、清除输出以及下载流程。下载流程非常有用,因为您可以将您的机器学习工作轻松地从流程转移到其他系统。
在右侧是单元对象操作下拉列表(如图图 2.10所示)。这个下拉列表也易于理解。它具有操作流程中各种单元格的基本功能。通常,它针对 Flow 笔记本中突出显示的单元格。您只需点击它就可以更改突出显示的单元格:
图 2.10 – 单元函数下拉列表
我们将在开始构建我们的机器学习流程时探索其他选项。
在本节中,我们了解了 H2O Flow 是什么,如何下载它,以及如何在本地启动它。此外,我们还探索了 H2O Flow UI 的各个部分以及它提供的各种功能。现在我们已经熟悉了我们的环境,让我们更深入地了解并创建我们的机器学习(ML)流程。我们将从流程的第一个部分开始,即处理数据。
在 H2O Flow 中与数据函数一起工作
机器学习流程始终从数据开始。您收集的数据量以及数据的质量在训练最高质量模型时起着非常关键的作用。如果数据的一部分与另一部分没有关系,或者如果存在大量不相关的噪声数据,那么模型的品质将相应降低。因此,在训练任何模型之前,我们通常会在将数据发送到模型训练之前对数据进行几个处理过程。H2O Flow 在其数据操作下拉列表中提供了所有这些过程的接口。
我们将逐步了解各种数据操作以及使用 H2O Flow 构建机器学习流程时的输出情况。
因此,让我们首先通过导入一个数据集来开始创建我们的机器学习流程。
导入数据集
本章我们将使用的数据集将是“心力衰竭预测”数据集。您可以在www.kaggle.com/fedesoriano/heart-failure-prediction
找到心力衰竭预测数据集的详细信息。
这是一个包含有关个体胆固醇、最大心率、心绞痛和其他属性的健康信息的数据集,这些属性是判断一个人是否可能经历心力衰竭的重要指标。
让我们了解数据集的内容:
-
Age: 患者的年龄,单位为年
-
Sex: 患者的性别;男性为 M,女性为 F
-
ChestPainType:
-
类型如下列出:
-
TA: 典型心绞痛
-
ATA: 不典型心绞痛
-
NAP: 非心绞痛疼痛
-
ASY: 无症状
-
-
-
RestingBP: 休息时的血压,单位为[毫米汞柱]
-
Cholesterol: 血清胆固醇,单位为[毫米/分升]
-
FastingBS: 空腹血糖,如果空腹血糖大于 120 mg/dl,则为 1,否则为 0
-
RestingECG: 休息时的心电图结果
-
类型如下列出:
-
Normal: 正常
-
ST: 存在 ST-T 波异常
-
LVH:根据 Estes 标准,显示可能或确定的左心室肥厚
-
-
-
MaxHR:达到的最大心率值,介于 60 和 202 之间
-
ExerciseAngina:运动诱导的心绞痛;Y 表示是,N 表示否
-
Oldpeak:ST(在下降时测量的数值)
-
ST_Slope:峰值运动 ST 段的斜率
-
类型如下:
-
上升:向上倾斜
-
Flat:平坦
-
下降:向下倾斜
-
-
-
HeartDisease:输出类别,其中 1 表示心脏病,0 表示无心脏病
我们将使用此数据集训练一个模型,尝试预测具有某些属性的人是否有面临心脏衰竭的潜力。请执行以下步骤:
-
首先,让我们开始使用 H2O Flow 导入此数据集。
-
在网页用户界面的最顶部,您可以看到 数据 对象操作的下拉列表。
-
点击它,网页用户界面应显示如下截图所示的输出:
图 2.11 – 数据对象下拉列表
下拉列表显示您可以执行的所有各种操作列表,以及与您将要处理的数据相关的那些操作。
函数列表如下:
-
导入文件:此操作导入存储在您系统中的文件。它们可以是任何可读的文件,可以是 逗号分隔值(CSV)格式或 Excel 格式。
-
导入 SQL 表:如果您使用 SQL 数据库存储任何表格数据,此操作允许您导入存储在您的 结构化查询语言(SQL)表中的数据。当您点击它时,您将被提示输入您的 SQL 数据库的 连接 URL 值,以及其凭据、表名称、列名称,以及选择 获取模式 的选项,可以是 分布式 或 单机,如下面的截图所示:
图 2.12 – 导入 SQL 表
-
上传文件:此操作从您的系统上传单个文件并立即解析它。
-
分割框架:此操作将已由 H2O Flow 导入和解析的数据框架分割成多个框架,您可以使用这些框架进行多个实验。
-
合并框架:此操作将多个框架合并为一个。当您点击它时,您将被提示选择右侧和左侧框架及其相应的列。此外,您可以选择包含在合并中的哪个框架的哪些行,如下面的截图所示:
图 2.13 – 合并框架
-
列出框架:此操作列出所有当前由 H2O 导入和解析的框架。如果您想要在不同的数据集上运行您的管道,这很有帮助,这些数据集之前已被您导入或拼接。
-
填充:填充是将数据集中缺失的值替换为平均值的过程,这样它不会引入任何偏差,最小化值,最大化值,甚至空值。此操作允许你根据你的偏好替换你的框架中的这些值。
因此,首先,让我们导入Heart Failure Prediction
数据集。
执行以下步骤:
-
点击数据操作下拉列表。
-
点击导入文件…。你应该会在你的流程中看到一个单元格上的操作被执行,如下面的截图所示:
图 2.14 – 导入文件
你也可以通过在单元格中键入importFiles
并按Shift + Enter直接运行相同的命令,而不是使用下拉列表。
-
在搜索栏中,添加你已下载数据集的文件夹位置。
-
点击最右侧的搜索按钮。这将显示文件夹中的所有文件,你可以选择要导入的文件。
-
选择
heart.csv
数据集,如下面的截图所示:
图 2.15 – 使用输入导入文件
- 一旦你选择了文件,点击导入按钮。然后 H2O 将导入数据集并显示如下输出:
图 2.16 – 导入的文件
恭喜!你现在已成功将你的数据集导入到 H2O Flow 中。下一步是将它解析成逻辑格式。让我们了解什么是解析以及我们如何在 H2O Flow 中完成它。
解析数据集
解析是将数据集中的信息字符串分析并加载到逻辑格式中的过程,在这种情况下,是一个hex文件。hex 文件是一种内容以十六进制格式存储的文件。H2O 在内部使用此文件类型进行数据框操作并维护数据集的元数据。
让我们通过执行以下步骤来解析新导入的数据集:
- 在导入数据集后,点击解析这些文件…按钮,如图图 2.16所示。
以下截图显示了你应该期望的输出:
图 2.17 – 数据集解析输入
-
然后,你将被提示输入
hex
文件。在解析过程中,你可以从以下配置中选择:-
来源:此配置表示你将要解析的数据集的来源。
-
ID:此配置表示数据集的 ID。你可以更改将要创建的 hex 文件的 ID。
-
解析器: 此配置设置用于解析数据集的解析器。您将使用不同的解析器来解析不同类型的数据集。例如,如果您正在解析 Parquet 文件,那么您需要选择 Parquet 文件解析器。在我们的情况下,我们正在解析 CSV 文件;因此,选择CSV解析器。您也可以将其设置为自动,H2O 将自行识别需要解析指定文件所需的解析器。
-
分隔符: 此配置用于指定分隔数据集中值的分隔符。让我们将其保留为默认值,,:’004’,这是一个非常常见的 CSV 分隔符值。
-
转义字符: 此配置用于指定数据集中使用的转义字符。让我们将其保留为默认值。
-
列标题: 此配置用于指定数据集的第一行是否包含列名。H2O 将使用此信息来处理第一行,要么将其用作列信息,要么自动生成列名并使用第一行作为数据值。此外,您可以将值设置为自动,让 H2O 自行识别数据集的第一行是否包含列名。我们的数据集的第一行是列名,所以让我们选择第一行包含列名。
-
选项: 此配置包含以下附加操作:
-
启用单引号作为字段引号字符: 此选项启用单引号作为字段引号字符。
-
完成时删除: 此选项在成功解析后删除导入的数据集。让我们勾选此选项,因为我们一旦成功解析就不会再需要导入的数据集。
-
-
-
在解析配置部分下方,您有编辑列名和类型部分(见图 2.18)。在解析数据集之前,H2O 读取数据集并显示列名和它们提取的信息类型的简要摘要。这给了您编辑列名和类型的选择,以防它解释错误或您希望将列名更改为不同的名称。
以下截图显示了列名和解析数据集时编辑它们类型的选项:
图 2.18 – 编辑列类型
现在,让我们简要了解列的类型,如前一个截图所示:
它们可以列出如下:
-
数值: 这表示该列中的值是数字。
-
枚举: 这表示该列中的值是枚举类型(Enums)。枚举是一组命名的非数值有限值集合。
-
时间: 这表示该列中的值是日期时间数据类型的值。
-
UUID: 这表示该列中的值是通用唯一标识符(UUIDs)。
-
字符串:这表示列中的值是字符串值。
-
无效:这表示列中的值无效,这意味着列中的值存在问题。
-
未知:这表示列中的值是未知的,这意味着列中没有值。
在训练过程中,H2O 根据列的类型不同对待数据框的列。有时,它会错误地解释列的值,并将错误的列类型分配给列。看看数据集的列及其对应类型。你可能会注意到,在导入数据集后,我们的HeartDisease输出列的类型是数值型。H2O 读取了 1 和 0,并假设它的类型是数值型。但实际上,它是一个枚举值,因为 1 表示心脏病,0 表示无心脏病。中间没有数值。我们在解析数据集时始终需要小心。我们需要确保在开始在该数据集上训练模型之前,H2O 正确地解释了数据集。H2O Flow 提供了一个在解析之前纠正这个问题的简单方法。
接下来,让我们纠正列的类型:
-
选择HeartDisease列名旁边的下拉列表,将其设置为枚举。
-
同样,FastingBS将被设置为数值型,但实际上,它是一个基于其描述的枚举值。所以,让我们将其设置为枚举。
-
现在我们已经纠正了列的类型,并选择了正确的解析配置,让我们解析数据集。点击输出底部的解析按钮。
以下截图显示了解析后的输出:
图 2.19 – 解析输出
现在,让我们观察从上一个截图得到的输出:
-
运行时间:这个输出显示了从 H2O 开始解析数据集以来的运行时间。
-
剩余时间:这个输出显示了 H2O 完成解析数据集预计所需的时间。
-
类型:这个输出显示了解析文件的类型。
-
键:这个输出显示了一个链接到十六进制文件,该文件是在成功解析后生成的。
-
描述:这个输出显示了当前正在进行的操作。
-
状态:这个输出显示了操作当前的状态。
-
进度:这个输出显示了操作的进度条。
-
操作:这个输出是一个按钮,显示在成功解析数据集后生成的十六进制文件。
恭喜!你已经成功解析了你的数据集,并生成了十六进制文件。十六进制文件通常被称为数据框。现在我们已经生成了数据框,让我们看看我们可以对数据框执行的各种元数据和操作。
观察数据框
数据框是 H2O 可以执行多个数据操作的主要数据对象。此外,H2O 还提供了关于数据框内容的详细见解和统计数据。当处理非常大的数据框时,这些见解特别有帮助,因为很难确定任何列中是否存在缺失值或零,而数据行可以从数千到数百万不等。
因此,让我们观察我们刚刚解析的数据框并探索其功能。您可以通过执行以下操作之一从我们在图 2.19中看到的解析输出中查看数据框:
-
在键行中单击
heart.hex
超链接。 -
在操作行中单击查看数据按钮。
以下截图显示了之前提到的操作的输出:
图 2.20 – 查看数据框
输出显示了数据框的摘要。在探索操作部分的各种操作之前,首先让我们探索下面的数据框元数据。
元数据包括以下内容:
-
行数:显示数据集中的行数。
-
列数:显示数据集中的列数。
-
压缩大小:显示数据框的总压缩大小。
在元数据下方,您有列摘要部分。在这里,您可以查看数据框内容的统计数据,这些数据按列划分。
摘要包含以下信息:
-
标签:此列显示了数据框列的名称。
-
类型:此列显示了列的类型。
-
缺失:此列显示了该列中缺失值的数量。
-
零:此列显示了该列中的零的数量。
-
+Inf:此列显示了正无穷值的数量。
-
-Inf:此列显示了负无穷值的数量。
-
min:此列显示了该列的最小值。
-
max:这显示了该列的最大值。
-
sigma:此列显示了该列值的变异性。
-
基数:此列显示了该列中唯一值的数量。
-
操作:此列显示了可以在数据框的列上执行的一些操作。这些操作主要涉及将列转换为不同类型。如果 H2O 在解析后错误地读取了列类型,这非常有用。
你可能想知道为什么在Sex和RestingECG等列的Zeros列中看到了很多值。这是因为编码。当解析枚举列时,H2O 将枚举和字符串编码成从 0 开始的数值,然后是 1,接着是 2,以此类推。你也可以通过选择你想要的编码过程来控制这个编码过程,例如,标签编码或独热编码。我们将在第五章中更详细地讨论编码,理解 AutoML 算法。
在COLUMN SUMMARIES部分之后,你会看到CHUNK COMPRESSION SUMMARY部分,如下截图所示:
图 2.21 – 数据集的 CHUNK COMPRESSION SUMMARY 部分
当使用非常大的数据集时,如果以传统方式读取和写入数据,可能会花费很长时间。因此,系统如 Hadoop 文件系统、Spark 等经常被使用,因为它们以分布式方式执行读写,比传统的连续方式更快。分块是一个过程,其中分布式文件系统如 Hadoop 将数据集分割成块并在写入磁盘之前将它们展平。H2O 内部处理所有这些,这样用户就不需要担心管理分布式读写。CHUNK COMPRESSION SUMMARY部分只是提供了关于块分布的额外信息。
在CHUNK COMPRESSION SUMMARY下方是FRAME DISTRIBUTION SUMMARY部分,如下截图所示:
图 2.22 – 数据集的 Frame Distribution Summary 部分
FRAME DISTRIBUTION SUMMARY部分提供了关于数据框的一般统计信息。如果你导入了多个文件并将它们解析成一个单一的数据框,那么框架分布摘要将计算总大小、平均大小、最小大小、最大大小、每个数据集的块数等等。
回顾一下图 2.20中的数据框,你可以看到列名被突出显示为链接。让我们点击最后一个列,HeartDisease。
下面的截图将展示HeartDisease列的列摘要:
图 2.23 – 列摘要
列摘要根据列的类型提供了关于数据集中各个列的更多详细信息。
对于像HeartDisease这样的枚举类型,它会显示如下列的详细信息:
-
特征:此图表显示了零值和非零值的百分比分布。
-
域:此图表显示了列的域,即一个值在总行数中被重复的次数。
当你将鼠标悬停在图表上时,你会看到更多详细信息。请随意探索所有列并尝试理解它们的特征。
返回到图 2.20的 dataframe,现在让我们看看操作部分。这包括可以在 dataframe 上执行的一些操作。
这些操作包括以下内容:
-
查看数据:此操作显示 dataframe 中的数据。
-
分割:此操作将 dataframe 按指定的比例分割成指定的部分。
-
构建模型:此操作在此 dataframe 上开始构建模型。
-
运行 AutoML:此操作会在 dataframe 上触发 AutoML。
-
预测:此操作使用 dataframe 在已训练的模型上进行预测并获取结果。
-
下载:此操作将 dataframe 下载到系统中。
-
导出:此操作将 dataframe 导出到系统中的指定路径。
尽管我们很兴奋要触发 AutoML,但让我们继续探索 dataframe 的各种功能。
现在,让我们看看 dataframe 及其实际的数据内容。为此,请在操作部分的查看数据按钮上点击。
以下截图显示了点击查看数据按钮的输出:
图 2.24 – dataframe 的内容视图
此功能显示数据集的实际内容。你可以向下滚动以查看 dataframe 的所有内容。如果你在 dataframe 上执行了任何操作,那么你可以使用此操作查看 dataframe 内容的变化。
现在你已经探索并理解了 dataframe 的各种操作和数据元数据,让我们调查另一个有趣的 dataframe 操作,称为分割。
分割 dataframe
在我们将 dataframe 发送进行模型训练之前,我们需要一个包含预测值的样本 dataframe。这个样本可以用来验证模型是否做出正确的预测,并衡量模型的准确性和性能。我们可以通过保留 dataframe 的一小部分用于后续验证来实现这一点。这就是分割功能出现的地方。
分割,正如其名所示,将数据集分割成我们可以后来用于不同操作的部分。数据集的分割会考虑比例。H2O 根据你想要进行的分割数量和数据分布的比例创建多个 dataframe。
要分割 dataframe,请在操作部分的分割操作按钮上点击。
以下截图显示了点击分割按钮的输出:
图 2.25 – 分割 dataframe
在前面的输出中,你将被提示输入分割配置,如下所示:
-
框架:此配置允许你选择要分割的框架。
-
training_dataframe
比例为 0.70 -
validation_dataframe
,比例为 0.20 -
testing_dataframe
,比例为 0.10 -
种子:此配置允许您选择随机化点。分割不是线性分割数据框。它随机分割数据框的行。这是好事,因为它在分割的数据框之间均匀分配数据,从而消除了数据集行序列中可能存在的任何偏差。在我们的演示中,让我们将种子值设置为 5。
一旦你进行了这些更改,点击创建按钮。这将生成三个数据框:training_dataframe、validation_dataframe和testing_dataframe。这三个框架将存储在 H2O 的本地存储库中,也可以用于其他实验。
以下图表显示了创建操作的结果:
图 2.26 – 分割数据集结果
这三个数据框都是独立的数据框,它们具有与你在图 2.20中看到的原始数据集相同的特征和选项。分割不会删除原始数据框。它创建新的数据框,并将原始数据框中的数据根据所选比例分配到这些数据框中。
现在我们已经准备好了训练框架、验证框架和测试框架,我们就可以进入模型训练管道的下一步,即模型训练。
因此,为了总结,在本节中,你了解了可以在 H2O Flow 中执行的多种数据操作,例如导入、解析、读取解析后的数据框以及分割它。
在下一节中,我们将专注于模型训练,并使用 H2O AutoML 在我们在本节中创建的数据框上训练模型。
在 H2O Flow 中与模型训练函数一起工作
一旦您的数据集准备就绪,模型训练管道的下一步就是实际的训练部分。模型的训练可能非常复杂,因为有许多配置决定了模型如何在数据集上训练。即使在 AutoML 中,大多数超参数调整也是在幕后完成的,这也是事实。不仅对于特定类型的数据,训练模型有正确和错误的方法,而且一些配置值也可能影响模型的表现。因此,了解 H2O 在训练模型时提供的各种配置参数非常重要。在本节中,我们将专注于了解这些参数是什么,以及它们在模型训练中的具体作用。
我们将通过使用我们之前创建的数据框,逐步了解如何使用 AutoML 训练模型。
注意,在这个部分有很多东西在这个阶段理解起来会过于复杂。我们将在未来的章节中探讨其中的一些。目前,我们将只关注我们现在可以理解的功能,因为本章的目标是理解 H2O Flow 以及如何使用 AutoML 通过 H2O Flow 训练模型。
在接下来的子章节中,我们将了解模型训练操作,从了解 AutoML 训练配置参数开始。
理解 H2O Flow 中的 AutoML 参数
H2O AutoML 在如何训练模型方面具有极高的可配置性。尽管使用相同的 AutoML 技术,但每个行业通常都会根据其需求对如何训练模型有一定的偏好或倾向。因此,尽管 AutoML 正在自动化大多数 ML 过程,但在 AutoML 如何训练模型方面仍需要一定程度的控制和灵活性。H2O 为其 AutoML 功能提供了广泛的配置能力。让我们在训练模型时探索它们。
有两种方式可以在数据集上触发 AutoML。它们如下列出:
-
通过点击数据框输出操作部分的运行 AutoML按钮,如图图 2.20所示。
-
通过在模型部分的下拉菜单中选择运行 AutoML,在网页 UI 的最顶部,如图图 2.27所示。
我们选择第二个选项,以便我们可以探索网页 UI 页面顶部的模型操作部分。当你点击模型部分时,你应该会看到一个下拉列表,如下面的截图所示:
图 2.27 – 模型功能下拉列表
上述下拉列表将模型操作分为三种类型,如下所示:
-
运行 AutoML:这个操作通过提示用户输入配置值来启动 AutoML 过程,以使用 AutoML 训练模型。
-
运行特定模型:这个操作在特定的 ML 算法上启动模型训练,这些算法是你希望使用的;例如,深度学习、K-means 聚类、随机森林等。每个 ML 算法都有一组你必须指定的参数,以启动模型训练。
-
模型管理选项:这些操作是用于管理你在一段时间内可能训练过的各种模型的基本操作。
-
操作列表如下:
-
导入 MOJO 模型:这个操作导入之前由另一个 H2O 服务训练并导出为 MOJO 格式的 H2O 模型对象,优化(MOJO)模型。
-
列出所有模型:这个操作列出由你的 H2O 服务训练的所有模型。这包括由其他 Flow 笔记本训练的模型。
-
列出网格搜索结果:网格搜索是一种在训练模型以获得最佳和最准确性能时寻找最佳超参数的技术。此操作列出从模型训练中获取的所有网格搜索结果。
-
导入模型:此操作将模型对象导入到 H2O 中。
-
导出模型:此操作将模型对象导出到系统,可以是二进制文件或 MOJO 格式。
-
-
现在,让我们使用 AutoML 在我们的数据集上训练我们的模型。
点击运行 AutoML。如图 2.27 所示,您应该看到一个提示您输入各种配置参数以运行 AutoML 的输出。有大量的选项可以配置您的 AutoML 训练。这些选项可以极大地影响您的模型训练性能以及最终训练出的模型质量。参数被分为三类。让我们逐一探索它们,并从基本参数开始,输入适合我们模型训练要求的值。
基本参数
基本参数是那些关注所有模型训练操作所需的基本输入的参数。这些参数在所有机器学习算法中都是通用的,并且是自我解释的。
以下截图显示了您需要输入以配置 AutoML 的基本参数值:
图 2.28 – AutoML 的基本参数
基本参数如下所示:
-
training_frame
参数是我们创建在使用 H2O Flow 中的数据函数部分中的training_dataframe.hex
文件。 -
HeartDisease
列。 -
我们在上一节中创建的
validation_dataframe.hex
文件。 -
blending_frame:此配置设置用于训练堆叠集成模型的 dataframe。目前,我们可以忽略这一点,因为我们不会在本章中深入探讨堆叠集成。我们将在第五章“理解 AutoML 算法”中更详细地探讨堆叠集成模型,所以让我们留空。
-
将
nfolds
设置为 0,然后 AutoML 将从训练框架生成排行榜。 -
项目名称:此配置设置您的项目名称。AutoML 将所有多次运行的结果组合到单个排行榜下,该排行榜以项目名称命名。如果您留空此值,H2O 将自动为其生成一个随机项目名称。
-
分布:此配置用于指定机器学习算法将使用的分布函数类型。支持指定类型分布函数的算法将使用它,而其他算法将使用它们的默认值。我们将在第五章“理解 AutoML 算法”中了解更多关于分布函数的内容。
现在您已经了解了 AutoML 的基本参数,让我们来了解高级参数。
高级参数
高级参数为使用 AutoML 训练模型提供了额外的配置。这些参数已经设置了某些默认值,因此不是必需的。然而,它们确实提供了额外的配置,这些配置会改变 AutoML 在训练模型时的行为。
下面的截图显示了 AutoML 的高级参数的第一部分:
图 2.29 – AutoML 高级参数,第一部分
立即在这之下将是高级参数的第二部分。向下滚动查看剩余的参数,如下面的截图所示:
图 2.30 – AutoML 高级参数,第二部分
让我们逐一探索这些参数。高级参数如下所示:
-
fold_column:此参数使用列值作为其 N 折交叉验证中折叠的基础。我们将在接下来的章节中学习更多关于交叉验证的内容。
-
weights_column:此参数为训练数据框中的某一列赋予权重,或者简单地说,给予该列优先权。我们将在后面的章节中更详细地探讨模型训练中的权重问题。
-
ignored_columns:此参数允许您选择在训练模型时希望忽略的训练数据框中的列。在我们的实验中,我们不会忽略任何列,所以我们将保留所有列未选中。
-
sort_metrics:此参数选择 AutoML 训练的模型将使用的排序和排名指标。选择AUTO将使用AUC指标进行二分类,mean_per_class_error用于多项式分类,以及deviance用于回归。为了简化起见,让我们将均方误差(MSE)设置为排序指标,因为它更容易理解。我们将在第六章中更详细地探讨指标,理解 H2O AutoML 排行榜和其他性能指标。
-
0
用于防止创建堆叠集成模型。我们将在接下来的章节中进一步探讨堆叠集成模型和交叉验证。 -
Balance_classes: 在模型训练中,始终最好在具有输出类别值均匀分布的数据集上训练模型。这可以减轻由于值分布不均可能产生的任何偏差。此参数平衡输出类别,使其数量相等。在我们的案例中,输出类别是心脏病列。正如我们在心脏病列的列摘要中看到的,在分布部分,我们有大约 410 个值为 0,508 个值为 1(见图 2.23)。因此,理想情况下,我们需要在训练模型之前平衡类别。然而,为了简化当前的操作,我们将跳过类别的平衡,专注于理解基础知识。我们将在接下来的章节中进一步探讨类别平衡。
-
exclude_algos: 此参数排除 AutoML 训练中的某些算法。在我们的实验中,我们希望考虑所有算法,所以让我们将值留空。
-
-1
保持原样。 -
monotone_constraints: 在某些情况下,如果对特征之间关系有非常强烈的先验信念,认为它们具有某种性质,可以使用约束来提高模型的预测性能。此参数有助于设置这些约束。我们将在接下来的章节中进一步讨论这个问题。现在,让我们将此值留空。
-
5
。 -
10
,否则模型训练可能会花费很长时间。 -
max_runtime_secs: 此参数设置 H2O 在训练单个模型上应花费的最大时间。通常,数据集的大小越大,模型训练所需的时间就越长。为模型训练设置非常短的时间将不会给 AutoML 足够的时间来训练模型。由于我们的数据集不是很大,我们将让 AutoML 有足够的时间来训练模型,这不应该花很长时间。
-
max_runtime_sec_per_model: 此参数设置 AutoML 在训练单个模型上应花费的最大时间。模型训练不会花费太多时间。所以,让我们忽略这个参数。
-
0
以禁用它。 -
stopping_metrics: 此指标用于早期停止。由于停止功能被禁用,我们将忽略此参数。
-
stopping_tolerance: 这指的是在渐进式模型训练中,当预期改进的相对容忍度低于此值时,AutoML 应停止训练模型。由于停止功能被禁用,我们将忽略此参数。
现在你已经了解了 AutoML 的基本参数,让我们检查专家参数。
专家参数
专家参数是提供额外选项的参数,这些选项通过添加有助于进一步实验的额外功能来补充 AutoML 训练结果。这些参数取决于你在高级参数部分已选定的配置。
以下截图显示了当前演练中可用的专家参数选项:
图 2.31 – AutoML 专家参数
专家参数如下列出:
-
keep_cross_validation_predictions:如果训练启用了交叉验证,那么 H2O 提供了保存那些预测值的选项。
-
keep_cross_validation_models:如果训练启用了交叉验证,那么 H2O 提供了保存用于相同训练的模型的选项。
-
keep_cross_validation_fold_assignments:如果训练启用了交叉验证,那么 H2O 提供了保存用于不同交叉验证中模型训练的折的选项。
-
export_checkpoint_dir:这是 H2O 将存储生成的模型的目录路径。
根据你在基本和高级参数中选择的内容,将提供更多专家选项。目前,我们可以禁用所有专家参数,因为我们在这个教程中不会过多关注它们。
一旦你设置了所有参数值,现在剩下的唯一事情就是触发 AutoML 模型训练。
在 H2O Flow 中使用 AutoML 训练和了解模型
模型训练是机器学习管道中最复杂和最重要的部分之一。模型训练是通过学习特征与预期输出之间的关系,通过最小化损失来映射数学近似的过程。你可以用各种方法来做这件事。系统执行此任务的方法被称为机器学习算法。AutoML 使用各种机器学习算法来训练模型,并比较它们的性能,以找到根据机器学习问题具有最小误差度量值的模型。
首先,让我们了解如何在 H2O Flow 中使用 AutoML 训练模型。
在 H2O Flow 中使用 AutoML 训练模型
当设置使用 AutoML 训练模型的参数值时,你需要仔细考虑。一旦你选择了正确的输入,你就可以触发 AutoML 模型训练。
你可以通过点击构建模型按钮在运行 AutoML输出的末尾来完成此操作。
以下截图显示了 AutoML 训练作业的进度:
图 2.32 – AutoML 训练已完成
训练模型需要一些时间。模型训练的结果存储在排行榜上。键部分的值是排行榜的链接(见图 2.32)。
你可以通过以下两种方式之一查看排行榜。它们如下列出:
-
点击 AutoML 训练作业输出中的键部分中的排行榜链接。
-
点击 AutoML 训练作业输出的查看按钮。
在以下截图中,你可以看到排行榜的样子:
图 2.33 – AutoML 排行榜
如果您遵循了前面示例中显示的相同步骤,那么您应该看到相同的输出,尽管模型的 ID 可能略有不同,因为它们是随机生成的。排行榜显示了 AutoML 训练的所有模型,并根据排序指标从最好到最差进行排名。排序指标是衡量模型质量的一种统计测量,用于比较不同模型的性能。此外,排行榜还包含所有单个模型详情的链接。您可以选择其中的任何一个来获取有关单个模型的更多信息。如果 AutoML 正在运行并正在训练模型,您还可以通过点击实时监控按钮来实时查看训练进度。
现在您已经了解了如何使用 AutoML 训练模型,让我们深入探讨机器学习模型细节,并尝试理解其各种特性。
理解机器学习模型
一个机器学习模型可以被描述为一个包含数学方程式的对象,该方程式可以识别给定特征集的模式并预测潜在的输出。这些机器学习模型构成了所有机器学习管道的核心组件,因为整个机器学习管道的目标是创建和使用这些模型进行预测。因此,了解训练好的机器学习模型的各个方面细节对于判断其做出的预测是否准确以及准确程度如何至关重要。
让我们点击排行榜上的最佳模型,以了解其更多细节。您应该看到以下输出:
图 2.34 – 模型信息
如您所见,H2O 提供了对模型细节的非常深入的视图。所有细节都分类在其各自的子节中。这里有很多信息,因此可能会让人感到不知所措。目前,我们将只关注重要的部分。
让我们逐一浏览重要且易于理解的细节:
-
模型 ID:这是模型的 ID。
-
算法:这表示用于训练模型的算法。
-
操作:一旦模型被训练,您可以对它执行以下操作:
-
刷新:这将刷新内存中的模型。
-
预测:这允许您开始在此模型上进行预测。
-
下载 POJO:这将以纯旧 Java 对象(POJO)格式下载模型。
-
下载模型部署包:这将以 MOJO 格式下载模型。
-
导出:这将以文件或 MOJO 格式将模型导出到系统。
-
检查:H2O 进入检查模式,其中它检查模型对象,检索有关其模式和子模式的详细信息。
-
删除:这将删除模型。
-
下载生成模型:这将下载生成的模型 JAR 文件。
-
然后,您将有一组子节,解释更多关于模型的元数据和性能。这些子节对于不同的模型略有不同,因为某些模型可能需要显示一些额外的元数据以供解释性目的。
如您所见,许多细节在本质上似乎非常复杂,这是理所当然的。这是因为它们涉及一些数据科学知识。请放心;我们将在接下来的章节中探讨所有这些内容。
让我们通过更容易的子节来了解 ML 模型的各个元数据:
-
模型参数: 模型参数不过是传递给 AutoML 的输入参数,以及 AutoML 决定用于训练模型的一些输入。您可以通过点击显示所有参数或显示修改参数按钮来选择查看所有参数或仅查看修改过的参数。每个参数的描述都显示在每个参数旁边。
-
变量重要性: 变量重要性表示变量在预测中的重要性。重要性最高的变量是 ML 模型在预测时最依赖的变量。任何对高重要性变量的更改都可能极大地影响模型预测。
以下截图显示了用于训练模型的 dataframe 中各种特征的缩放重要性:
图 2.35 – 变量重要性
- 输出: 输出子节表示 AutoML 训练的基本输出值。显示的大多数细节都是交叉验证结果。
输出值如下所示:
-
模型类别: 此值表示模型的类别,表示它执行何种预测。二项式表示它执行二项式分类,这意味着它预测值是1还是0。在我们的案例中,1表示该人可能面临心脏病,而0表示该人不太可能面临心脏病。
-
开始时间: 此值表示模型训练开始的 epoch 时间。
-
结束时间: 此值表示模型训练结束时的 epoch 时间。
-
运行时间: 此值表示完成模型训练所需的总时间。
-
默认阈值: 这是模型将所有预测视为1的默认阈值。同样,低于默认阈值的任何预测值将被视为0。
以下截图显示了模型详细信息输出子节:
图 2.36 – 模型信息输出
- 列类型: 本小节为您简要介绍了数据框中列的类型。这些值与训练数据框中列的顺序相同。
下面的截图显示了模型细节的列类型指标:
图 2.37 – 列类型
- 输出 - 训练指标:此子部分显示了当使用训练数据集进行预测时模型的指标。我们将在未来的章节中学习有关机器学习各种指标的内容。
下面的截图显示了模型细节的训练指标:
图 2.38 – 模型输出的训练指标
- 输出 - 验证指标:类似于前面的子部分,此子部分显示了当使用验证数据集进行预测时模型的指标。
下面的截图显示了模型细节的训练指标:
图 2.39 – 模型输出的验证指标
现在我们已经了解了模型细节的各个部分,让我们看看我们如何可以对这个新训练的模型进行预测。
在 H2O Flow 中使用预测函数
现在你终于有一个训练好的模型了,我们可以在它上面进行预测。对训练好的模型进行预测很简单。你只需要加载模型,并传入你的数据集,该数据集包含你想要进行预测的数据。H2O 将使用加载的模型并对数据集中的所有值进行预测。让我们使用之前创建的 prediction_dataframe.hex
数据框来进行预测。
在接下来的子部分中,我们将了解预测操作,首先了解如何进行预测。
使用 H2O Flow 进行预测
首先,让我们从探索网页 UI 顶部的评分操作下拉列表开始。
你将看到以下评分操作的列表:
图 2.40 – 评分函数下拉菜单
前面的下拉菜单显示了你可以执行的所有各种评分操作的列表。
函数列表如下:
-
预测:这使用训练好的模型进行预测。
-
部分依赖图:这些显示了变量对预测的影响的图形表示。换句话说,它们显示了在用于预测的数据中改变某些变量如何影响预测响应。
-
列出所有预测:此功能列出所有已进行的预测。
你可以在 H2O Flow 中开始进行预测有两种方式。如下所示:
-
使用来自评分操作下拉菜单的预测函数。
-
在模型的操作部分点击预测按钮,如图 2.34 所示。
这两种方法都会给出相同的结果,如下面的截图所示:
图 2.41 – 预测
点击 ML 模型的预测操作按钮将模型参数设置为相应的模型 ID。然而,当在分数操作下拉列表中点击预测操作按钮时,您可以选择任何模型。
预测操作将提示您以下参数:
-
名称:您可以给预测结果命名,以便更容易识别。如果您正在尝试不同的预测请求,并且需要快速参考您感兴趣的特定预测结果,这将特别有用。
-
模型:这是您希望用于进行预测的模型的 ID。由于我们选择了梯度提升机(GBM)模型的预测操作,这将不可编辑。
-
框架:这是您想要用于进行预测的数据框。因此,让我们选择prediction_dataset.hex文件。
-
计算叶节点分配:这返回了用于进行预测的数据框中每一行的行在模型的所有树中的叶节点位置。在我们的演示中,我们不需要这个功能,因此我们可以将其保持未选中状态。
一旦您选择了适当的参数值,剩下的唯一事情就是点击预测按钮来执行您的预测。
以下截图显示了预测操作的输出:
图 2.42 – 预测输出
恭喜!您终于成功地在由 AutoML 训练的模型上进行了预测。让我们继续到下一部分,我们将探索和理解我们刚刚得到的预测结果。
理解预测结果
预测是机器学习流程的最终阶段。它是将实际值带给所有投入创建机器学习流程的努力的部分。进行预测很容易;然而,理解实际预测值及其与输入值的关系是很重要的。
预测结果不仅提供了预测值的详细信息,还包括指标信息和某些元数据,如图 2.42 所示。
以下截图显示了您预测结果的预测输出子部分:
图 2.43 – 预测结果
这与我们在图 2.38和图 2.39中看到的模型详细信息的输出 - 验证和训练指标类似。
在这个子部分中,您可以在预测键旁边找到预测框架链接。点击它将显示您预测值的框架摘要。让我们这样做,以便我们可以更好地查看预测值。
以下截图显示了以数据框形式呈现的预测摘要详细信息:
图 2.44 – 预测数据框
H2O 也将预测结果存储为数据框,因此它们具有我们在在 H2O Flow 中处理数据函数部分讨论的相同特性。
列摘要部分指示了预测数据框中的三列。它们如下列出:
-
预测:此列是枚举类型,表示预测数据框中输入行的预测值。
-
P0:此列表示预测值为 0 的概率。
-
P1:此列表示预测值为 1 的概率。
让我们查看数据以更好地理解其内容。你可以通过点击预测数据框输出中的操作部分的查看数据按钮来查看数据框的内容,如图 2.44 所示。
以下截图显示了查看预测数据时的预期输出:
图 2.45 – 预测数据框的内容
让我们回到预测输出的预测子部分,如图 2.43 所示。让我们将预测结果与用作预测输入的数据框合并。你可以通过点击将预测与框架合并按钮来完成此操作。
以下截图显示了该操作的输出:
图 2.46 – 将预测与框架合并的结果
点击查看框架按钮会显示合并框架,它也是一个数据框。让我们点击查看框架按钮来查看框架的内容。
以下截图显示了从框架合并输出中的查看框架操作的输出:
图 2.47 – 用于预测的数据框与预测结果的合并
在合并预测输出的操作部分的查看数据按钮中选择,会显示包含预测值的完整数据框内容。
以下截图显示了合并数据框的内容:
图 2.48 – 合并数据框的内容
观察合并数据框的内容,你会注意到你现在可以轻松地比较预测值,如预测列中提到的,以及与同一行中的HeartDisease列的实际值进行比较。
恭喜!你已经正式对一个你训练的模型进行了预测,并将结果合并到一个单独的数据框中,以便进行比较查看,你可以与你的利益相关者分享。因此,这总结了我们的 H2O Flow 创建 ML 管道的教程。
摘要
在本章中,我们了解了 H2O Flow 提供的各种功能。在熟悉了 Web UI 之后,我们开始实现我们的机器学习流程。我们导入了并解析了心力衰竭预测数据集。我们了解了可以在数据框上执行的各种操作,了解了数据框的元数据和统计数据,并为后续的训练、验证和预测模型做好了准备。
然后,我们使用 AutoML 在数据框上训练模型。我们了解了需要输入的各种参数,以正确配置 AutoML。我们使用 AutoML 训练模型并理解了排行榜。然后,我们更深入地研究了训练模型的细节,并尽力理解它们的特征。
在我们的模型训练完成后,我们对它进行了预测,并通过将其与原始数据框结合来探索预测输出,以便我们可以比较预测值。
在下一章中,我们将进一步探索各种数据操作操作。这将帮助我们了解在数据清洗和转换数据框方面需要采取哪些步骤,以及它如何提高训练模型的品质。
第二部分 H2O AutoML 深入探讨
本部分将帮助您理解 H2O AutoML 的内部工作原理。这包括 H2O AutoML 如何处理数据处理、训练和模型选择,以及它是如何衡量训练模型性能的。本部分还将帮助您理解如何阅读各种性能图表和其他模型细节,这些细节将有助于理解模型的行为。所有这些都将帮助您进一步实验和探索 H2O AutoML,并根据您的需求最大限度地利用它。
本节包括以下章节:
-
第三章,理解数据处理
-
第四章,理解 H2O AutoML 训练和架构
-
第五章,理解 AutoML 算法
-
第六章,理解 H2O AutoML 排行榜和其他性能指标
-
第七章,与模型可解释性工作
第三章:理解数据处理
机器学习(ML)模型是在数据拟合到 ML 算法后得到的输出。它代表了各种特征之间的潜在关系以及这种关系如何影响目标变量。这种关系完全取决于数据集的内容。尽管使用相同的 ML 算法,但每个 ML 模型都是独特的,这是因为用于训练该模型的特定数据集。数据可以从各种来源收集,并且可以具有不同的模式和结构,它们之间可能不需要结构上兼容,但实际上可能相互关联。这种关系可能非常有价值,也可能潜在地成为好模型和坏模型之间的区别。因此,将数据转换为满足 ML 算法的要求,最终训练出一个好模型是很重要的。
数据处理、数据准备和数据预处理都是 ML 管道中的步骤,它们通过转换数据结构来最佳地暴露特征之间的潜在关系。数据处理可能是 ML 管道中最具挑战性的步骤,因为转换过程没有固定的步骤。数据处理完全取决于您希望解决的问题;然而,所有数据集之间都有一些相似之处,这可以帮助我们定义可以执行以优化 ML 管道的某些过程。
在本章中,我们将了解一些在数据处理中经常使用的常见功能,以及 H2O 内置的操作如何帮助我们轻松地执行它们。我们将了解一些可以重构我们数据框结构的 H2O 操作。我们将了解如何处理缺失值以及值插补的重要性。然后,我们将研究如何操作数据框中的各种特征列,以及如何根据不同的需求切片数据框。我们还将研究编码是什么以及不同的编码类型。
在本章中,我们将涵盖以下主要主题:
-
重构你的数据框
-
处理数据框中的缺失值
-
操作数据框的特征列
-
文本数据的分词
-
使用目标编码对数据进行编码
技术要求
本章中的所有代码示例都是在Jupyter Notebook上运行的,以便于理解代码块中每一行的操作。您可以通过 Python 或 R 脚本执行器运行整个代码块并观察输出结果,或者您可以通过安装 Jupyter Notebook 并观察代码块中每一行的执行结果来跟随操作。
要安装 Jupyter Notebook,请确保您的系统上安装了最新版本的 Python 和pip
,并执行以下命令:
pip install jupyterlab
一旦 JupyterLab 成功安装,您可以通过在终端执行以下命令来在本地启动 Jupyter Notebook:
jupyter notebook
这将在你的默认浏览器上打开 Jupyter Notebook 页面。然后你可以选择你想要使用的语言并开始逐步执行代码步骤。
本章的所有代码示例都可以在 GitHub 上找到,网址为 github.com/PacktPublishing/Practical-Automated-Machine-Learning-on-H2O/tree/main/Chapter%203
。
现在,让我们通过首先创建一个 dataframe 并将其重新格式化以满足我们的模型训练要求来开始处理我们的数据。
重新格式化你的 dataframe
从各种来源收集的数据通常被称为 原始数据。它被称为原始数据,是因为其中可能包含很多不必要的或过时的数据,这些数据可能不会必然有利于我们的模型训练。收集到的数据结构也可能在所有来源之间不一致。因此,首先将来自各种来源的数据重新格式化为一致格式变得非常重要。
你可能已经注意到,一旦我们将数据集导入 H2O,H2O 会将数据集转换为 .hex
文件,也称为 dataframe。你也可以选择导入多个数据集。假设你正在从各种来源导入多个数据集,每个数据集都有自己的格式和结构,那么你需要一个特定的功能来帮助你重新格式化数据集的内容并将它们合并成一个可以输入到你的机器学习流程中的单个 dataframe。
H2O 提供了几个你可以用来执行所需操作的功能。
这里有一些 dataframe 操作功能,可以帮助你重新格式化你的 dataframe:
-
将两个数据框的列合并
-
将两个数据框的行合并
-
合并两个数据框
让我们看看如何在 H2O 中将来自不同 dataframe 的列合并。
将两个数据框的列合并
最常见的 dataframe 操作功能之一是从不同的 dataframe 中合并不同的列。有时,一个 dataframe 的列可能与另一个 dataframe 的列相关。这在模型训练期间可能是有益的。因此,拥有一个可以帮助我们操作这些列并将它们合并成一个用于模型训练的单个 dataframe 的功能是非常有用的。
H2O 有一个名为 cbind()
的函数,可以将一个数据集的列合并到另一个数据集中。
让我们在我们的 Jupyter Notebook 中使用 Python 尝试这个函数。按顺序执行以下步骤:
-
导入
h2o
库:import h2o
-
导入
numpy
库;我们将使用它来创建一个用于我们研究的样本 dataframe:import numpy as np
-
初始化
h2o
服务器:h2o.init()
-
现在,让我们创建一个名为
important_dataframe_1
的数据框;这是一个列很重要的数据框。为了确保你在数据集中生成的值与这个例子中的相同,将numpy
的随机种子值设置为123
。我们将设置行数为15
,列数为5
。你可以给列取任何你喜欢的名字:np.random.seed(123) important_dataframe_1 = h2o.H2OFrame.from_python(np.random.randn(15,5).tolist(), column_names=list([" important_column_1" , " important_column_2" , " important_column_3" , " important_column_4" , " important_column_5" ]))
-
让我们通过执行以下代码来查看数据集的内容:
important_dataframe_1.describe
以下截图显示了数据集的内容:
图 3.1 – important_dataframe_1 数据内容
-
让我们创建另一个名为
important_dataframe_2
的数据框,就像之前一样,但具有不同的列名,但行数相等,只有2
列:important_dataframe_2 = h2o.H2OFrame.from_python(np.random.randn(15,2).tolist(), column_names=list([" important_column_6" , " important_column_7" ]))
-
让我们查看这个数据框的内容:
图 3.2 – important_dataframe_2 数据内容
-
现在,让我们使用
cbind()
函数将两个数据框的列合并,并将它们存储在另一个名为final_dataframe
的变量中:final_dataframe = important_dataframe_1.cbind(important_dataframe_2)
-
现在,让我们观察
final_dataframe
:final_dataframe.describe
你应该看到final_dataframe的内容如下:
图 3.3 – cbind()后的 final_dataframe 数据内容
在这里,你会注意到我们已经成功地将important_dataframe_2
的列与important_dataframe_1的列合并在一起。
这就是如何使用cbind()
函数将两个不同数据集的列合并成一个单一的数据框。在使用cbind()
函数时需要注意的唯一一点是,要确保要合并的两个数据集具有相同数量的行。此外,如果你有具有相同列名的数据框,那么 H2O 将在数据框的列名前添加一个0。
现在我们已经知道了如何合并不同数据框的列,让我们看看如何将具有相同列结构的多数据框的列值合并在一起。
合并两个数据框的行
大多数大型企业通常处理大量的数据。这些数据通常被分成多个块,以便更快、更有效地存储和读取。然而,在模型训练期间,我们经常需要访问所有这些分区的数据集。这些数据集具有相同的结构,但数据内容是分布的。换句话说,数据框具有相同的列;然而,数据值或行被分散在它们之间。我们经常需要一个函数将所有这些数据框合并在一起,以便我们有所有数据值可用于模型训练。
H2O 有一个名为rbind()
的函数,可以将一个数据集的行合并到另一个数据集中。
让我们在以下示例中尝试这个函数:
-
导入
h2o
库:import h2o
-
导入
numpy
库;我们将使用它来创建用于我们研究的随机数据框:import numpy as np
-
初始化
h2o
服务器:h2o.init()
-
现在,让我们创建一个名为
important_dataframe_1
的随机数据框。为了确保你在数据集中生成与这个例子相同的值,将numpy
的随机种子值设置为123
。我们将设置行数为15
,列数为5
。你可以给列取任何你喜欢的名字:np.random.seed(123) important_dataframe_1 = h2o.H2OFrame.from_python(np.random.randn(15,5).tolist(), column_names=list([" important_column_1" , " important_column_2" ," important_column_3" ," important_column_4" ," important_column_5" ]))
-
让我们查看数据框的行数,它应该是
15
:important_dataframe_1.nrows
-
让我们创建另一个名为
important_dataframe_2
的数据框,就像之前的一个一样,具有相同的列名和任意数量的行。在示例中,我使用了10
行:important_dataframe_2 = h2o.H2OFrame.from_python(np.random.randn(10,5).tolist(), column_names=list([" important_column_1" , " important_column_2" ," important_column_3" ," important_column_4" ," important_column_5" ]))
-
让我们查看
important_dataframe_2
的行数,它应该是10
:important_dataframe_2.nrows
-
现在,让我们使用
rbind()
函数将两个数据框的行合并并存储在另一个名为final_dataframe
的变量中:final_dataframe = important_dataframe_1.rbind(important_dataframe_2)
-
现在,让我们观察
final_dataframe
:final_dataframe.describe
你应该看到final_dataframe的内容如下:
图 3.4 – 使用 rbind()后的 final_dataframe 数据内容
-
让我们查看final_dataframe的行数:
final_dataframe.nrows
最后一个操作的输出应该显示最终数据集的行数。你会看到值是25,数据框的内容是前两个数据集的合并行值。
现在我们已经了解了如何在 H2O 中使用rbind()
函数合并两个数据框的行,让我们看看我们如何完全合并两个数据集。
合并两个数据框
你可以直接合并两个数据框,将它们的行和列合并成一个数据框。H2O 提供了一个merge()
函数,用于合并具有公共列或公共列的两个数据集。在合并过程中,两个数据集共有的列用作合并键。如果它们只有一个公共列,那么这个列形成合并的单个主键。如果有多个公共列,那么 H2O 将根据这些列的数据值形成所有这些列的复杂键,并将其用作合并键。如果两个数据集之间有多个公共列,而你只想合并特定的子集,那么你需要重命名其他公共列以消除相应的公共性。
让我们在下面的 Python 示例中尝试这个函数:
-
导入
h2o
库:import h2o
-
导入
numpy
库;我们将使用它来创建一个用于我们研究的随机数据框:import numpy as np
-
初始化
h2o
服务器:h2o.init()
-
现在,让我们创建一个名为
dataframe_1
的数据框。该数据框有3
列:words
、numerical_representation
和letters
。现在,让我们按照以下内容填写数据内容:dataframe_1 = h2o.H2OFrame.from_python({'words':['Hello', 'World', 'Welcome', 'To', 'Machine', 'Learning'], 'numerical_representation': [0,1,2,3,4,5],'letters':['a','b','c','d']})
-
让我们查看数据集的内容:
dataframe_1.describe
-
你将注意到数据集的内容如下:
图 3.5 – dataframe_1 数据内容
-
让我们创建另一个名为
dataframe_2
的数据框。这个数据框也包含3
列:numerical_representation
列、letters
列(这两个列与dataframe_1
相同),以及一个不常见的列。让我们称它为other_words
:dataframe_2 = h2o.H2OFrame.from_python({'other_words':['How', 'Are', 'You', 'Doing', 'Today', 'My', 'Friend', 'Learning', 'H2O', 'Artificial', 'Intelligence'], 'numerical_representation': [0,1,2,3,4,5,6,7,8,9],'letters':['a','b','c','d','e']})
-
让我们查看这个数据框的内容:
dataframe_2.head(11)
执行代码后,你应该在你的笔记本中看到以下输出:
图 3.6 – dataframe_2 数据内容
-
现在,让我们使用
merge()
操作将dataframe_1
合并到dataframe_2
中:final_dataframe = dataframe_2.merge(dataframe_1)
-
让我们现在观察
final_dataframe
:final_dataframe.describe
-
你应该看到 final_dataframe 的内容如下:
图 3.7 – merge() 后的 final_dataframe 内容
你会注意到 H2O 使用了 numerical_representation
列与其他列中适当的值的组合。
现在,你可能想知道为什么没有 4 这一行的数据。那是因为在合并过程中,我们有两个共同的列:numerical_representation 和 letters。所以,H2O 使用了一个复杂的合并键,它同时使用了这两个列:(0,a)、(1,b)、(2,c),以此类推。
现在你可能有的下一个问题是 关于值 5 的那一行,它在 letters 列中没有值。 那是因为在机器学习中,即使是空值也被视为一个独特的值。因此,在合并过程中,生成的复杂键将 (5,) 视为一个有效的合并键。
H2O 丢弃了所有剩余的值,因为 dataframe_1 没有更多的数值表示值。
-
你可以通过将
all_x
参数设置为True
来强制 H2O 不丢弃合并键列中的任何值,如下所示:final_dataframe = dataframe_2.merge(dataframe_1, all_x = True)
-
现在,让我们观察
describe
属性的内容:
图 3.8 – 强制 merge() 后的 final_dataframe 数据内容
你会注意到我们现在将两个 dataframe 的所有值合并到一个单一的 dataframe 中。我们有了从 0 到 9 的所有数值表示,以及从 dataframe_2 中缺失的 a 到 e 的所有字母,以及来自 other_words 列和 words 列的正确值。
回顾一下,我们学习了如何合并 dataframe 的列和行。我们还学习了如何使用 merge()
函数将整个 dataframe 合并在一起。然而,我们注意到,即使数据框的关键列中没有共同的数据值,我们强制合并数据框时,最终在 dataframe 中出现了缺失值。
现在,让我们看看我们可以使用哪些不同的方法来处理 H2O 中的缺失值。
处理 dataframe 中的缺失值
在实际世界中,数据集中的缺失值是最常见的问题。通常,在从各种来源收集的大量数据块中,至少会有几个缺失数据的实例。数据可能因为多种原因而缺失,从数据在源头未生成到数据收集器的停机等。处理缺失数据对于模型训练非常重要,因为许多机器学习算法不支持缺失数据。那些支持缺失数据的算法可能会更重视寻找缺失数据中的模式,而不是实际存在的数据,这会分散机器学习的注意力。
缺失数据通常被称为不可用(NA)或nan。在我们可以将数据框发送给模型训练之前,我们需要首先处理这些类型的值。您可以选择删除包含任何缺失值的整个行,或者用默认值填充这些值,这些默认值可以是该数据列的默认值或常见值。您如何处理缺失值完全取决于哪些数据缺失以及这对于整体模型训练的重要性。
H2O 提供了一些功能,您可以使用这些功能来处理数据框中的缺失值。以下是一些例子:
-
fillna()
函数 -
在框架中替换值
-
估算
接下来,让我们看看如何使用 H2O 在数据框中填充缺失值。
填充 NA 值
fillna()
是 H2O 中的一个函数,您可以使用它以顺序方式填充缺失数据值。如果您有一个列中的某些数据值是按顺序排列的,例如时间序列或任何按顺序增加或减少的度量,并且可以排序,那么这个功能特别有用。序列中值的差异越小,这个函数就越适用。
fillna()
函数有以下参数:
-
method
:这可以是前向或后向。它表示 H2O 在数据框中开始填充 NA 值的方向。 -
axis
:0
表示按列填充,1
表示按行填充。 -
maxlen
:要填充的最大连续 NA 值数。
让我们通过 Python 的例子来看看我们如何使用这个函数来填充缺失值:
-
导入
h2o
库:import h2o
-
导入
numpy
库;我们将使用它来创建用于我们研究的随机数据框:import numpy as np
-
初始化
h2o
服务器:h2o.init()
-
创建一个包含
1000
行、3
列和一些 NA 值的随机数据框:dataframe = h2o.create_frame(rows=1000, cols=3, integer_fraction=1.0, integer_range=100, missing_fraction=0.2, seed=123)
-
让我们观察这个数据框的内容。执行以下代码,您将在数据框中看到某些缺失值:
dataframe.describe
您应该看到数据框的内容如下:
图 3.9 – 数据框内容
-
现在我们使用
fillna()
函数来前向填充 NA 值。执行以下代码:filled_dataframe = dataframe.fillna(method=" forward" , axis=0, maxlen=1)
-
让我们观察填充后的数据框内容。执行以下代码:
filled_dataframe.describe
-
您应该看到数据框的内容如下:
图 3.10 – 填充后的数据框内容
fillna()
函数已按顺序填充数据框中的大多数 NA 值。
然而,你会注意到我们仍然有一些NA
。由于这是第一列,H2O 在记录中没有先前的值来填充它,因此它跳过了它。
现在我们已经了解了如何使用 H2O 中的fillna()
函数按顺序在数据框中填充数据,让我们看看我们如何替换数据框中的某些值。
替换数据框中的值
数据处理中经常需要的一种常见功能是替换数据框中的某些值。你可能想这样做的原因有很多。这在数值数据中尤为常见,其中一些最常用的转换包括舍入值、规范化数值范围或只是纠正数据值。在本节中,我们将探讨我们可以在 H2O 中使用的一些函数来替换数据框中的值。
让我们首先创建一个我们可以用来测试这些函数的数据框。执行以下代码,以便我们有一个可以操作的数据框:
import h2o
h2o.init()
dataframe = h2o.create_frame(rows=10, cols=3, real_range=100, integer_fraction=1, missing_fraction=0.1, seed=5)
dataframe.describe
数据框应该看起来如下所示:
图 3.11 – 数据框数据内容
因此,我们有一个包含三个列:C1、C2和C3的数据框。每个列都有几个负数和一些nan值。让我们看看我们如何处理这个数据框。
让我们从简单的事情开始。让我们更新单个数据值,也称为99
。你可以根据其在数据框中的位置更新单个数据值的值,如下所示:
dataframe[3,1] = 99
注意,数据框中的列和行都从0
开始。因此,我们将行号为3
、列号为1
的值设置为99
。你可以通过执行以下dataframe.describe
来在数据框中看到结果:
dataframe.describe
数据框应该看起来如下所示:
图 3.12 – 数据更新后的数据框内容
正如你在数据框中看到的,我们将之前位于C2列第三行的nan值替换为99。
这只是一个数据值的操作。让我们看看我们如何替换整个列的值。让我们将C3列的数据值增加到原始值的 3 倍。你可以通过执行以下代码来实现:
dataframe[2] = 3*dataframe[2]
你可以通过执行以下dataframe.describe
来在数据框中看到结果:
dataframe.describe
数据框应该看起来如下所示:
图 3.13 – 列值更新后的数据框内容
我们可以在输出中看到,C3列的值现在已增加到原始列值的 3 倍。
我们到目前为止所执行的所有替换都是直接的。让我们尝试在数据框上进行一些条件更新。让我们将数据框中的所有负数四舍五入到0
。所以,条件是我们只更新负数为0
,不更改任何正数。您可以进行如下条件更新:
dataframe[dataframe['C1'] < 0, " C1" ] = 0
dataframe[dataframe['C2'] < 0, " C2" ] = 0
dataframe[dataframe['C2'] < 0, " C3" ] = 0
您可以通过执行以下dataframe.describe
来在数据框中看到结果:
dataframe.describe
数据框应如下所示:
图 3.14 – 条件更新后的数据框内容
如您在数据框中所见,所有负值都已向上舍入/替换为0。
现在,如果我们不想将负数向上舍入到0,而是希望仅反转负数,我们可以通过结合条件更新和算术更新来实现。请参考以下示例:
dataframe[" C1" ] = (dataframe[" C1" ] < 0).ifelse(-1*dataframe[" C1" ], dataframe[" C1" ])
dataframe[" C2" ] = (dataframe[" C2" ] < 0).ifelse(-1*dataframe[" C2" ], dataframe[" C2" ])
dataframe[" C3" ] = (dataframe[" C3" ] < 0).ifelse(-1*dataframe[" C3" ], dataframe[" C3" ])
现在,让我们尝试看看我们是否可以替换剩余的fillna()
函数,但如果nan值只是某些缺失值,这些值并不完全符合任何递增或递减模式,而我们只想将其设置为 0 怎么办?让我们现在就做。运行以下代码:
dataframe[dataframe[" C1" ].isna(), " C1" ] = 0
dataframe[dataframe[" C2" ].isna(), " C2" ] = 0
dataframe[dataframe[" C3" ].isna(), " C3" ] = 0
您可以通过执行以下dataframe.describe
来在数据框中看到结果:
dataframe.describe
数据框应如下所示:
图 3.15 – 替换 nan 值为 0 后的数据框内容
isna()
函数是一个检查数据中的值是否为nan的函数,并返回True或False。我们使用这个条件来替换数据框中的值。
提示
在数据框中操作和替换值有多种方法,H2O 提供了丰富的功能来简化实现。请随意探索和实验更多关于操作数据框中的值。您可以在以下链接中找到更多详细信息:docs.h2o.ai/h2o/latest-stable/h2o-py/docs/frame.xhtml
。
现在我们已经学习了在数据框中替换值的各种方法,让我们看看数据科学家和工程师经常采用的一种更高级的方法。
补充
之前,我们看到了如何使用fillna()
函数在数据集中替换 nan 值,该函数按顺序替换 dataframe 中的 nan 数据。fillna()
函数以顺序方式填充数据;然而,数据不一定总是具有顺序性。例如,考虑一个关于购买游戏笔记本电脑的人的数据集。该数据集将主要包含 13-28 岁年龄段的关于人的数据,还有一些异常值。在这种情况下,如果fillna()
函数中有任何 nan 值用于填充 nan 值,那么任何异常值之后的任何 nan 值都会在 dataframe 中引入偏差。我们需要用一个在产品年龄组的标准分布中常见的值来替换 nan 值,这个值在 13 和 28 之间,而不是像 59 这样的值,因为 59 出现的可能性较小。
假设是替换 dataframe 中某些值的过程,用适当的替代值替换,这些替代值不会引入任何可能影响模型训练的偏差或异常值。用于计算替代值的计算方法被称为假设策略。假设是数据处理中最重要的一种方法,它处理缺失和 nan 值,并试图用可能对模型训练过程引入最少偏差的值来替换它们。
H2O 有一个名为impute()
的函数,专门提供此功能。它有以下参数:
-
column
: 此参数接受要设置impute()
列号的列。值1
假设整个 dataframe。 -
method
: 此参数设置要使用的假设方法。方法可以是mean
、median
或mode
。 -
combine_method
: 此参数指定当选择median
作为假设方法时,如何组合偶数样本的量数。组合方法可以是interpolate
、average
、low
或high
。 -
group_by_frame
: 此参数假设所选预计算的分组框架的值。 -
by
: 此参数按所选列对假设结果进行分组。 -
values
: 此参数接受一个列表,其中包含每列的值。列表中的None
值会跳过该列。
让我们通过一个 Python 示例来看看我们如何使用此函数来填充缺失值。
对于这个,我们将使用高中学生短跑数据集。高中学生短跑数据集是一个包含高中学生年龄、体重、最大记录速度和 100 米短跑表现的记录数据集。该数据集用于预测年龄、体重和短跑速度如何影响学生在 100 米短跑比赛中的表现。
数据集看起来如下:
图 3.16 – 一位高中学生的短跑数据集
数据集的特征如下:
-
年龄:学生的年龄
-
体重:学生的体重(千克)
-
max_speed:学生每小时的最大冲刺速度(千米/小时)
-
100_meter_time:学生完成 100 米冲刺所需的时间(秒)
如你所见,100_meter_time列中有很多缺失值。
我们不能简单地使用fillna()
函数,因为这会在缺失值恰好发生在最快或最慢时间之后时引入数据偏差。我们也不能简单地用常数替换这些值。
实际上,替换这些缺失值,用平均青少年 100 米冲刺的正常值来替换是有意义的。我们已经有大多数学生的数据,所以我们可以使用他们的结果来计算一个一般的 100 米冲刺平均时间,并以此作为基准来替换所有缺失值,而不会引入任何偏差。
这正是填充缺失值所用的。让我们使用填充函数来填充这些缺失值:
-
导入
h20
模块并启动h20
服务器:import h2o h2o.init()
-
我们然后使用
h2o.import_file()
导入高中学生冲刺
数据集:dataframe = h2o.import_file(" Dataset/high_school_student_sprint.csv" )
-
使用
impute()
函数,让我们通过mean
来填充100_meter_time
列中的缺失值,并显示数据:dataframe.impute(" 100_meter_time" , method = " mean" ) dataframe.describe
你将看到以下填充后的数据框输出:
图 3.17 – 使用平均值填充的 100 米时间列
- H2O 计算了100_meter_time列所有值的平均值为23.5558,并用它替换了缺失值。
类似地,你还可以使用median
值来代替mean
。然而,请注意,如果某一列包含分类值,那么方法必须是mode
。这个决定取决于你,根据最有助于替换缺失值的 dataset:
dataframe.impute(" 100_meter_time" , method = " median" )
dataframe.impute(" 100_meter_time" , method = " mode" )
-
让我们稍微增加一下复杂性。如果平均 100 米冲刺时间在所有学生之间并不真正可比,会怎样?如果按年龄比较,表现会更相似呢?例如,16 岁的学生比 13 岁的学生跑得快,因为他们身体发育得更成熟。在这种情况下,在填充 16 岁学生的缺失值时考虑 13 岁学生的冲刺时间就没有意义了。这就是我们可以使用
impute()
函数的group
参数的地方:dataframe = h2o.import_file(" Dataset/high_school_student_sprint.csv" ) dataframe.impute(" 100_meter_time" , method = " mean" , by=[" age" ]) dataframe.describe
你将看到以下输出:
图 3.18 – 使用其平均值填充的 100 米冲刺数据,并按年龄分组
你会注意到现在 H2O 已经按年龄计算了平均值,并用它替换了相应年龄的mean
值,在所有impute()
函数中灵活地填充正确的值。
impute()
函数在填充数据框中的正确值方面非常强大。通过列以及框架进行分组的附加参数使其在处理各种缺失值时非常灵活。
随意使用和探索这些函数在不同的数据集上。最终,所有这些函数都是数据科学家和工程师用来提高数据质量的工具;真正的技能是理解何时以及如何使用这些工具从您的数据中获得最大收益,这需要实验和实践。
现在我们已经了解了我们可以用不同的方式处理缺失数据,让我们继续到数据处理过程的下一部分,即如何操纵 dataframe 的特征列。
操纵 dataframe 的特征列
在大多数情况下,您数据处理活动将主要涉及操纵数据框的列。最重要的是,列中的值类型和列中值的顺序将在模型训练中发挥重要作用。
H2O 提供了一些功能,可以帮助您做到这一点。以下是一些帮助您处理 dataframe 中缺失值的功能:
-
列排序
-
改变列的类型
让我们首先了解如何使用 H2O 对列进行排序。
列排序
理想情况下,您希望在将数据传递给模型训练之前对 dataframe 中的数据进行洗牌。然而,可能存在某些场景,您可能希望根据列中的值重新排序 dataframe。
H2O 有一个名为 sort()
的功能,可以根据列中的值对 dataframe 进行排序。它有以下参数:
-
by
:要排序的列。您也可以通过列表传递多个列名。 -
ascending
:一个表示 H2O 应该按什么方向排序列的布尔数组。如果为True
,则 H2O 将按升序排序该列。如果为False
,则 H2O 将按降序排序。如果没有传递任何标志,则 H2O 默认按升序排序。
H2O 将如何排序 dataframe 取决于是否将单个列名传递给 sort()
函数或多个列名。如果只传递单个列名,则 H2O 将返回一个按该列排序的框架。
然而,如果传递了多个列,则 H2O 将返回一个按以下方式排序的数据框:
-
H2O 首先将对传递给参数的第一个列对 dataframe 进行排序。
-
H2O 将根据传递给参数的下一列对 dataframe 进行排序,但只有与第一排序列中相同的值的行才会被排序。如果前几列中没有重复值,则不会对后续列进行排序。
让我们通过一个 Python 示例来看看我们如何使用此函数来排序列:
-
导入
h2o
库并初始化它:import h2o h2o.init()
-
执行以下代码创建一个 dataframe 并观察数据集:
dataframe = h2o.H2OFrame.from_python({'C1': [3,3,3,0,12,13,1,8,8,14,15,2,3,8,8],'C2':[1,5,3,6,8,6,8,7,6,5,1,2,3,6,6],'C3':[15,14,13,12,11,10,9,8,7,6,5,4,3,2,1]}) dataframe.describe
数据集的内容应如下所示:
图 3.19 – dataframe_1 数据内容
-
因此,目前,列
sort()
函数中的值被放入by
参数中,表示数据框的第一列,或者通过传递[‘C1’],这是一个包含列名的列表,按顺序对数据集进行排序:sorted_dataframe_1 = dataframe.sort(0) sorted_dataframe_1.describe
你应该得到以下代码的输出:
图 3.20 – 按 C1 列排序的 dataframe_1
你会发现数据框现在已按C1列的升序排序。
-
让我们看看如果我们通过
by
参数传递多个列来按多个列排序,我们会得到什么。运行以下代码行:sorted_dataframe_2 = dataframe.sort(['C1','C2']) sorted_dataframe_2.describe
你应该得到以下输出:
图 3.21 – 按列 C1 和 C2 排序的 dataframe_1
如你所见,H2O 首先使用sort
函数对列进行排序。
-
你也可以通过在
ascending
参数中传递False
来反转排序顺序。让我们通过运行以下代码行来测试一下:sorted_dataframe_3 = dataframe.sort(by=['C1','C2'], ascending=[True,False]) sorted_dataframe_3.describe
你应该看到以下输出:
图 3.22 – dataframe_1 按 C1 列升序排序,按 C2 列降序排序
在这种情况下,H2O 首先按C1列对列进行排序。然后,对于在C1列中具有相同值的行,它按C2列对这些行进行排序。然而,这次它是按降序排序的。
现在你已经学会了如何按单列以及多列对数据框进行排序,让我们继续学习另一个更改列类型的列操作函数。
更改列类型
正如我们在第二章中看到的,使用 H2O Flow (H2O 的 Web UI),我们将Heart Disease
列的类型从numerical
更改为enum
。我们这样做的原因是列的类型在模型训练中起着重要作用。在模型训练期间,列的类型决定了 ML 问题是分类问题还是回归问题。尽管这两种情况中的数据本质上都是数值的,但 ML 算法如何处理该列完全取决于其类型。因此,在数据收集的初始阶段可能未正确设置列类型时,正确设置列类型变得非常重要。
H2O 有几个函数不仅可以帮助你更改列的类型,还可以对列类型进行初始检查。
其中一些函数如下:
-
.isnumeric()
: 检查数据框中的列是否为数值类型。相应地返回True
或False
-
.asnumeric()
: 为指定列创建一个新框架,其中所有值都转换为数值 -
.isfactor()
: 检查数据框中的列是否为分类类型。相应地返回True
或False
-
.asfactor()
: 为指定列创建一个新框架,其中所有值都转换为分类类型 -
.isstring()
: 检查数据框中的列是否为字符串类型。相应地返回True
或False
-
.ascharacter()
: 为指定列创建一个新框架,其中所有值都转换为字符串类型
让我们看看如何在 Python 中使用这些函数来更改列类型的一个例子:
-
导入
h2o
库并初始化 H2O:import h2o h2o.init()
-
执行以下代码行创建一个数据框并观察数据集:
dataframe = h2o.H2OFrame.from_python({'C1': [3,3,3,0,12,13,1,8,8,14,15,2,3,8,8],'C2':[1,5,3,6,8,6,8,7,6,5,1,2,3,6,6],'C3':[15,14,13,12,11,10,9,8,7,6,5,4,3,2,1]}) dataframe.describe
数据集的内容应该是这样的:
图 3.23 – 数据框数据内容
-
让我们通过使用
isnumeric()
函数来确认numerical
列如下:dataframe['C1'].isnumeric()
你应该得到一个True
的输出。
-
让我们看看如果我们使用
asfactor()
函数检查categorical
列会得到什么:dataframe['C1'].isfactor()
你应该得到一个False
的输出。
-
现在,让我们使用
asfactor()
函数将categorical
列转换为因子类型,然后检查isfactor()
是否返回True
:dataframe['C1'] = dataframe['C1'].asfactor() dataframe['C1'].isfactor()
你现在应该得到一个True
的输出。
-
你可以使用
asnumeric()
函数将numerical
列转换为数值类型:dataframe['C1'] = dataframe['C1'].asnumeric() dataframe['C1'].isnumeric()
你现在应该得到一个True
的输出。
现在你已经学会了如何对数据框的列进行排序和更改列类型,让我们继续学习数据处理中的另一个重要主题,即分词和编码。
文本数据的分词
并非所有机器学习算法(MLAs)都专注于数学问题解决。自然语言处理(NLP)是机器学习的一个分支,它专门分析从文本数据中提取的意义,尽管它也会尝试从文档或任何文本中提取意义和理解内容。训练 NLP 模型可能非常棘手,因为每种语言都有其自己的语法规则,某些单词的解释在很大程度上依赖于上下文。尽管如此,NLP 算法通常会尽力训练一个可以预测文本文档的意义和情感的模型。
训练 NLP 算法的方法是首先将文本数据块分解成更小的单元,称为标记。标记可以是单词、字符,甚至是字母。这取决于 MLA 的要求以及它是如何使用这些标记来训练模型的。
H2O 有一个名为tokenize()
的函数,它可以帮助将数据框中的字符串数据分解成标记,并为进一步处理创建一个包含所有标记的单独列。
它有以下参数:split
:我们在该参数中传递一个正则表达式,该表达式将由函数用于将文本数据分割成标记。
让我们看看如何使用这个函数在数据框中对字符串数据进行分词的例子:
-
导入
h2o
库并初始化它:import h2o h2o.init()
-
执行以下代码行创建一个数据框并观察数据集:
dataframe1 = h2o.H2OFrame.from_python({'C1':['Today we learn AI', 'Tomorrow AI learns us', 'Today and Tomorrow are same', 'Us and AI are same']}) dataframe1 = dataframe1.ascharacter() dataframe1.describe
数据集应该看起来如下所示:
图 3.24 – 数据框数据内容
这种类型的文本数据通常在生成大量日志文本或对话数据的系统中收集。为了解决这类自然语言处理任务,我们需要将句子分解成单个标记,以便我们最终可以构建这些文本的上下文和意义,这将有助于机器学习算法进行语义预测。然而,在深入研究自然语言处理的复杂性之前,数据科学家和工程师将首先通过分词来处理这些数据。
-
让我们使用这个函数来分词我们的数据框,观察分词后的列:
tokenized_dataframe = dataframe1.tokenize(" " ) tokenized_dataframe
你应该看到以下数据框:
图 3.25 – 分词后的数据框内容
你会注意到tokenize()
函数将文本数据分割成标记,并将标记作为行附加到单个列中。你还会注意到所有分词后的句子都由空行分隔。你可以通过使用nrows
比较数据框中所有句子的单词数量以及句子之间的空格与分词数据集的行数来交叉检查这一点。
这些是在将数据输入到机器学习管道进行训练之前用于处理数据的常用数据处理方法。还有许多方法和技巧可以用来进一步清理和抛光数据框。如此之多,以至于你可以专门写一本书来讨论它们。数据处理恰好是整个机器学习生命周期中最困难的部分。用于训练的数据质量取决于问题陈述的上下文。它还取决于数据科学家和工程师在处理数据时的创造力和独创性。数据处理的目标是从数据集中提取尽可能多的信息,并从数据中去除噪声和偏差,以便在训练期间进行更有效的数据分析。
使用目标编码进行数据编码
正如我们所知,机器只能理解数字。然而,许多现实世界的机器学习问题都围绕着非数字性质的对象和信息。例如,状态、名称和类别等通常被表示为类别而不是数字。这种数据被称为分类数据。分类数据在分析和预测中通常会扮演重要角色。因此,有必要将这些分类值转换为数值格式,以便机器能够理解它们。这种转换还应该以这种方式进行,即我们不会失去这些类别的固有含义,也不会向数据中引入新的信息,例如数字的增量性质等。
这就是编码被使用的地方。编码是一个过程,其中分类值被转换,换句话说,编码为数值。有许多编码方法可以执行这种转换。其中最常用的一种是目标编码。
目标编码是一种编码过程,通过计算给定类别中目标变量发生的平均概率,将分类值转换为数值。H2O 也有帮助用户在数据上实现目标编码的方法。
为了更好地理解这种方法,考虑以下示例神话生物
数据集:
图 3.26 – 我们的神话生物数据集
此数据集包含以下内容:
-
动物:此列包含动物名称的分类值。
-
神话:此列包含0的二进制值和1的二进制值。1表示生物是神话中的,而0表示生物不是神话中的。
现在,让我们使用目标编码来编码分类列。目标编码将执行以下步骤:
- 将分类值分组,并记录给定类别中目标值神话为1和为0的次数如下:
图 3.27 – 带有目标计数的神话生物数据集
- 计算在特定组内1的目标值发生的概率,与0的目标值相比。这看起来如下所示:
图 3.28 – 带有目标 1 发生概率列的神话生物数据集
- 删除动物列,并使用目标 1 发生概率列作为动物列的编码表示。新的编码数据集将如下所示:
图 3.29 – 目标编码的神话生物数据集
在编码数据集中,动物特征使用目标编码进行编码,我们得到了一个完全数值化的数据集。这个数据集将很容易被机器学习算法解释和学习,从而提供高质量的模型。
让我们看看如何使用 H2O 进行目标编码。我们将使用此示例的汽车价格预测
数据集。您可以在archive.ics.uci.edu/ml/datasets/Automobile
(Dua, D. 和 Graff, C. (2019). UCI 机器学习库[archive.ics.uci.edu/ml
]。加州大学欧文分校信息与计算机科学学院,加州,欧文)找到该数据集的详细信息。
该数据集相当直接。它包含有关汽车的各种详细信息,例如汽车的制造商、发动机尺寸、燃油系统、压缩比和价格。机器学习算法的目标是根据这些特征预测汽车的价格。
在我们的实验中,我们将使用目标编码对categorical
列make、fuel type和body style进行编码,其中price列是目标。
让我们按照以下示例执行目标编码:
-
导入
h2o
和 H2O 的H2OTargetEncoderEstimator
,并初始化你的 H2O 服务器。执行以下代码:import h2o from h2o.estimators import H2OTargetEncoderEstimator h2o.init()
-
导入
Automobile price prediction
数据集并打印数据集的内容。执行以下代码:automobile_dataframe = h2o.import_file(" Dataset\Automobile_data.csv" ) automobile_dataframe
让我们观察数据框的内容;它应该如下所示:
图 3.30 – 汽车价格预测数据框
如前图所示,数据框包含大量列,其中包含汽车的详细信息。为了理解目标编码,让我们筛选出我们想要实验的列,同时删除其余的列。由于我们计划对make
列、fuel-type
列和body-style
列进行编码,让我们只使用这些列以及price
响应列。执行以下代码:
automobile_dataframe = automobile_dataframe[:,[" make" , " fuel-type" , " body-style" , " price" ]]
automobile_dataframe
过滤后的数据框将如下所示:
图 3.31 – 过滤列的汽车价格预测数据框
-
现在让我们将这个数据框拆分为训练数据框和测试数据框。执行以下代码:
automobile_dataframe_for_training, automobile_dataframe_for_test = automobile_dataframe.split_frame(ratios = [.8], seed = 123)
-
现在让我们使用
H2OTargetEncoderEstimator
训练我们的目标编码器模型。执行以下代码:automobile_te = H2OTargetEncoderEstimator() automobile_te.train(x= [" make" , " fuel-type" , " body-style" ], y=" price" , training_frame=automobile_dataframe_for_training)
一旦目标编码器完成训练,你将看到以下输出:
图 3.32 – 目标编码器训练的结果
从前面的截图可以看出,H2O 目标编码器将为make
列、fuel-type
列和body-style
列生成目标编码值,并分别存储在不同的名为make_te
、fuel-type_te
和body-style_te
的列中。这些新列将包含编码值。
-
现在让我们使用这个训练过的目标编码器对训练数据集进行编码并打印编码后的数据框:
te_automobile_dataframe_for_training = automobile_te.transform(frame=automobile_dataframe_for_training, as_training=True) te_automobile_dataframe_for_training
编码后的训练帧应如下所示:
图 3.33 – 编码的汽车价格预测训练数据框
如图中所示,我们的训练帧现在有三个额外的列,make_te
、fuel-type_te
和body-style_te
,包含数值。这些是make
列、fuel-type
列和body-style
列的目标编码列。
-
同样,现在让我们使用训练好的目标编码器来编码测试数据框架,并打印编码后的数据框架。执行以下代码:
te_automobile_dataframe_for_test = automobile_te.transform(frame=automobile_dataframe_for_test, noise=0) te_automobile_dataframe_for_test
编码后的测试框架应如下所示:
图 3.34 – 编码的汽车价格预测测试数据框架
如您从图中所示,我们的测试框架也有三个额外的列,这些是编码列。现在您可以使用这些数据框架来训练您的机器学习模型。
根据您的下一步行动,您可以使用编码后的数据框架以您认为合适的方式。如果您想使用数据框架来训练机器学习模型,那么您可以删除数据框架中的分类
列,并使用相应的编码列作为训练特征来训练您的模型。如果您希望对数据集进行任何进一步的统计分析,那么您可以保留这两种类型的列,并进行任何比较研究。
小贴士
H2O 的目标编码器有几个参数可以设置以调整编码过程。根据您正在处理的数据类型,为目标编码数据集选择正确的设置可能会变得非常复杂。因此,请随意尝试这个功能,因为您对这个功能和目标编码的一般理解越好,您就能更好地编码数据框架并进一步提高模型训练。您可以在以下位置找到有关 H2O 目标编码器的更多详细信息:docs.h2o.ai/h2o/latest-stable/h2o-docs/data-science/target-encoding.xhtml
。
恭喜!您刚刚了解了如何使用 H2O 的目标编码器对分类值进行编码。
摘要
在本章中,我们首先探讨了我们在将数据框架发送到模型训练之前所使用的各种技术和一些常见函数,以预处理我们的数据框架。我们探讨了如何将原始数据框架重新构建成适合的、一致的格式,以满足模型训练的要求。我们学习了如何通过将不同数据框架的不同列组合起来来操作数据框架的列。我们还学习了如何从分区数据框架中组合行,以及如何直接将数据框架合并成一个单一的数据框架。
一旦我们学会了如何重新构建我们的数据框架,我们就学会了如何处理新收集的数据中经常出现的缺失值。我们学会了如何填充 NA 值,替换某些错误值,以及如何使用不同的插补策略来避免在填充缺失值时添加噪声和偏差。
然后,我们研究了如何通过按列排序数据框架以及更改列的类型来操作特征列。我们还学习了如何对字符串进行标记化以处理文本数据,以及如何使用 H2O 的目标编码器对分类值进行编码。
在下一章中,我们将打开 AutoML 的“黑箱”,探索其训练过程,以及 AutoML 过程中内部发生的事情。这将帮助我们更好地理解 H2O 如何施展魔法并高效地自动化模型训练过程。
第四章:理解 H2O AutoML 架构和训练
模型训练是机器学习(ML)管道的核心组件之一。它是管道中系统读取和理解数据集中模式的一步。这种学习输出数据集中不同特征与目标值之间关系的数学表示。系统读取和分析数据的方式取决于所使用的 ML 算法和其复杂性。这就是 ML 的主要复杂性所在。每个 ML 算法都有其自己的方式来解释数据并从中提取信息。每个 ML 算法都旨在优化某些指标,同时权衡某些偏差和方差。H2O AutoML 所做的自动化进一步复杂化了这一概念。试图理解它是如何工作的可能会让许多工程师感到不知所措。
不要因为这种复杂性而气馁。所有复杂的系统都可以分解成简单的组件。理解这些组件及其相互之间的交互有助于我们理解整个系统。同样,在本章中,我们将打开黑盒,即 H2O 的 AutoML 服务,并尝试理解是什么魔法使得机器学习的自动化成为可能。我们首先将了解 H2O 的架构。我们将将其分解成简单的组件,然后理解 H2O 的各个组件之间发生什么样的交互。稍后,我们将了解 H2O AutoML 如何训练如此多的模型,并能够优化它们的超参数以获得最佳模型。
在本章中,我们将涵盖以下主题:
-
观察 H2O 的高级架构
-
了解客户端与 H2O 服务之间交互的流程
-
理解 H2O AutoML 如何进行超参数优化和训练
因此,让我们首先了解 H2O 的架构。
观察 H2O 的高级架构
要深入了解 H2O 技术,我们首先需要了解其高级架构。这不仅有助于我们理解构成 H2O AI 堆栈的不同软件组件,还有助于我们理解这些组件之间如何相互交互以及它们的依赖关系。
在这个前提下,让我们看一下 H2O AI 的高级架构,如下所示:
图 4.1 – H2O AI 高级架构
H2O AI 架构在概念上分为两部分,每一部分在软件堆栈中都有不同的作用。这两部分如下:
-
客户端层 – 这一层指向与 H2O 服务器通信的客户端代码。
-
Java 虚拟机(JVM)组件 – 这一层表示 H2O 服务器及其所有负责 H2O AI 不同功能的 JVM 组件,包括 AutoML。
客户端和 JVM 组件层之间由 网络层 分隔。网络层不过是普通的互联网,请求就是通过它发送的。
让我们深入到每一层,以更好地理解它们的职能,从第一层,客户端层开始。
观察客户端层
客户端层包括您在系统中安装的所有客户端代码。您使用这个软件程序向 H2O 服务器发送请求以执行您的机器学习活动。以下图表显示了 H2O 高级架构中的客户端层:
图 4.2 – H2O 高级架构的客户层
每种受支持的语言都将拥有自己的 H2O 客户端代码,这些代码将在相应语言的脚本中安装和使用。所有客户端代码内部通过套接字连接,通过 REST API 与 H2O 服务器通信。
以下 H2O 客户端分别适用于相应的语言:
-
JavaScript:H2O 的嵌入式 Web UI 是用 JavaScript 编写的。当您启动 H2O 服务器时,它启动一个托管在 http://localhost:54321 的 JavaScript Web 客户端。您可以使用 Web 浏览器登录此客户端,并与 H2O 服务器通信以执行您的机器学习活动。JavaScript 客户端通过 REST API 与 H2O 服务器通信。
-
library(h2o)
然后使用导入的H2O
变量导入数据集并训练模型。这是与初始化的 H2O 服务器交互的 R 客户端,它使用 REST API 进行交互。 -
import h2o
然后使用导入的H2O
变量来指挥 H2O 服务器。这是使用 REST API 与 H2O 服务器交互的 Python 客户端。 -
Excel:Microsoft Excel 是微软为 Windows、macOS、Android 和 iOS 开发的电子表格软件。由于它是处理大量二维数据的最广泛使用的电子表格软件,因此 H2O 也支持 Microsoft Excel。H2O 还有一个针对 Microsoft Excel 的客户端,它允许 Excel 用户通过 Excel 客户端使用 H2O 进行机器学习活动。
-
Tableau:Tableau 是交互式数据可视化软件,它帮助数据分析师和科学家以图表和图形的形式可视化数据,这些图表和图形本质上是交互式的。H2O 支持 Tableau,因此有一个专门的 Tableau 客户端,它为 Tableau 摄入的数据添加了机器学习功能。
-
Flow:如 第二章 中所述,使用 H2O Flow (H2O 的 Web UI),H2O Flow 是 H2O 的 Web 用户界面,它具有在笔记本式界面中设置整个机器学习生命周期的所有功能。该界面内部运行在 JavaScript 上,并且同样通过标准 REST API 与 H2O 服务器通信。
以下图表显示了各种 H2O 客户端与同一 H2O 服务器的交互:
图 4.3 – 不同客户端与同一 H2O 服务器通信
如图中所示,所有不同的客户端都可以与同一实例的 H2O 服务器通信。这使得单个 H2O 服务器能够服务用不同语言编写的不同软件产品。
这涵盖了客户端层的所有内容;让我们继续向下移动到 H2O 高级架构的下一层,即 JVM 组件层。
观察 JVM 组件层
JVM 是一个运行时引擎,它在您的系统中运行 Java 程序。H2O 云服务器在多个JVM 进程上运行,也称为JVM 节点。每个 JVM 节点运行 H2O 软件堆栈的特定组件。
下图显示了构成 H2O 服务器的各种 JVM 组件:
图 4.4 – H2O JVM 组件层
如前图所示,JVM 节点进一步分为三个不同的层级,具体如下:
-
Shalala Scala
库是一个代码库,它访问用户可以用来编写自己的程序和算法的专用领域特定语言,这些程序和算法 H2O 可以使用。 -
算法层:该层包含 H2O 提供的所有内置机器学习算法。该层的 JVM 进程负责执行所有机器学习活动,如导入数据集、解析、为相应的机器学习算法计算数学,以及整体训练模型。该层还包含预测引擎,其进程使用训练好的模型执行预测和评分功能。任何导入到 H2O 中的自定义算法也位于这一层,JVM 进程的处理方式与其他算法相同。
-
资源管理层:该层包含所有负责在执行机器学习活动时高效管理系统资源(如内存和 CPU)的 JVM 进程。
该层中的一些 JVM 进程如下:
-
流体向量框架:框架,也称为 DataFrame,是 H2O 中的基本数据存储对象。流体向量是 H2O 的工程师们创造的一个术语,它指的是 DataFrame 中的列可以通过高效(或者说,流动)的方式添加、更新或删除,与数据工程领域的 DataFrame 相比,后者通常被认为是不可变的。
-
分布式键值存储:键值存储或数据库是一个数据存储系统,它通过使用索引键从分布式存储系统中高效快速地检索数据或值。H2O 在其集群中使用这种分布式键值内存存储,以实现快速存储和查找。
-
NonBlockingHashMap:通常在数据库中,为了提供 原子性、一致性、隔离性和持久性(ACID)属性,当对数据进行更新时,会使用锁定来锁定数据。这阻止了多个进程访问同一资源。H2O 使用一个 NonBlockingHashMap,这是 ConcurrentHashMap 的一个实现,具有更好的扩展能力。
-
Job:在编程中,一个工作就是一个大型的工作,由软件执行,服务于单一目的。H2O 使用一个作业管理器来协调执行各种复杂任务的作业,如高效的数学计算和减少 CPU 资源消耗。
-
MRTask:H2O 使用其自己的内存中 MapReduce 任务来执行其机器学习活动。MapReduce 是一种编程模型,用于通过在分布式集群上并行执行任务来处理大量计算或数据读取和写入。MapReduce 有助于系统比顺序计算更快地执行计算活动。
-
Fork/Join:H2O 使用一个名为 jsr166y 的修改版 Java 并发库来执行任务的并发执行。jsr166y 是一个非常轻量级的任务执行框架,它使用 Fork,其中进程将任务分解成更小的子任务,以及 Join,其中进程将子任务的输出结果合并以获得任务的最终输出。
整个 JVM 组件层位于 Spark 和 Hadoop 数据处理系统之上。JVM 层的组件利用这些数据处理集群管理引擎来支持集群计算。
这总结了 H2O 软件技术的整个高级架构。考虑到这个背景,让我们进入下一节,我们将了解客户端与 H2O 之间的交互流程以及客户端-服务器交互如何帮助我们执行机器学习活动。
了解客户端与 H2O 服务之间交互的流程
在第一章,理解 H2O AutoML 基础,以及第二章,使用 H2O Flow (H2O 的 Web UI)中,我们看到了如何向 H2O 发送命令来导入数据集或训练模型。让我们尝试理解当您向 H2O 服务器发送请求时幕后发生的事情,从数据摄取开始。
在数据摄取期间了解 H2O 客户端-服务器交互
系统摄取数据的过程与我们在现实生活中读书的方式相同:我们打开书本,逐行阅读。同样,当你想让你的程序读取存储在系统中的数据集时,你首先需要通知程序数据集的位置。然后程序会打开文件,逐行读取数据的字节,并将其存储在其 RAM 中。然而,在机器学习(ML)中,这种顺序数据读取的问题在于数据集往往非常大。这类数据通常被称为大数据,其体积可以从千兆字节到太字节不等。无论系统有多快,读取如此大量的数据都需要相当长的时间。这是机器学习管道所没有的时间,因为机器学习管道的目标是做出预测。如果做出决策的时间已经过去,这些预测将没有任何价值。例如,如果你设计了一个安装在汽车中的机器学习系统,该系统能够在检测到碰撞的可能性时自动停车,那么如果该系统花费所有时间读取数据,并且无法在碰撞发生之前及时做出预测,那么这个机器学习系统将毫无用处。
这就是并行计算或集群计算发挥作用的地方。一个集群不过是通过网络连接在一起,表现得像一个单一实体的多个进程。集群计算的主要目的是通过这些多个进程并行化长时间运行的顺序任务,以快速完成任务。这就是为什么集群计算在机器学习管道中扮演着非常重要的角色。H2O 也正确地使用了集群来摄取数据。
让我们观察数据摄取交互请求是如何从 H2O 客户端流向 H2O 服务器,以及 H2O 是如何摄取数据的。
参考以下图表以了解数据摄取交互的流程:
图 4.5 – H2O 数据摄取请求交互流程
以下步骤序列描述了客户端请求 H2O 集群服务器摄取数据的过程,H2O 使用Hadoop 分布式文件系统(HDFS)来提供服务:
-
发起请求:一旦 H2O 集群服务器启动并运行,使用 H2O 客户端的用户将发起一个指向数据集位置的摄取数据函数调用(参见图 4.5中的步骤 1)。Python 中的函数调用如下所示:
h2o.import_file("Dataset/iris.data")
H2O 客户端将从函数调用中提取数据集位置,并在内部创建一个 REST API 请求(参见图 4.5中的步骤 2)。然后客户端将通过网络将请求发送到 H2O 服务器所在的 IP 地址。
- H2O 服务器处理请求:一旦 H2O 集群服务器从客户端接收到 HTTP 请求,它将提取请求中的数据集位置路径值并启动分布式数据集摄取过程(参见 图 4.5 中的 步骤 3)。然后集群节点将协调并并行化从给定路径读取数据集的任务(参见 图 4.5 中的 步骤 4)。
每个节点将读取数据集的一部分并将其存储在其集群内存中。
- 数据摄取:从数据集位置路径读取的数据将存储在分布式 H2OFrame 集群内存中的块中(参见 图 4.6 中的 步骤 1)。数据块存储在分布式键值存储中(参见 图 4.6 中的 步骤 2)。一旦数据完全摄取,H2O 服务器将创建一个指针,该指针指向存储在键值存储中的摄取数据集,并将其返回给请求的客户端(参见 图 4.6 中的 步骤 3)。
参考以下图表以了解数据摄取后 H2O 返回响应时的交互流程:
图 4.6 – H2O 数据摄取响应交互流程
一旦客户端收到响应,它将创建一个包含此指针的 DataFrame 对象,用户随后可以使用该指针在摄取的数据集上运行任何进一步的执行(参见 图 4.6 中的 步骤 4)。通过使用指针和分布式键值存储,H2O 可以在 DataFrame 操作和使用上工作,而无需在服务器和客户端之间传输它摄取的大量数据。
现在我们已经了解了 H2O 如何摄取数据,让我们现在看看它是如何处理模型训练请求的。
了解 H2O 在模型训练期间的交互序列
在模型训练过程中,有许多交互发生,从用户发起模型训练请求到用户获取训练好的机器学习模型。H2O 的各个组件通过一系列协调的消息和计划好的作业执行模型训练活动。
为了更好地理解当模型训练请求发送到 H2O 服务器时内部发生的情况,我们需要深入了解模型训练期间发生的交互序列。
我们将通过以下方式对交互序列进行分类来理解它们:
-
客户端启动模型训练作业。
-
H2O 执行模型训练作业。
-
客户端轮询作业完成状态。
-
客户端查询模型信息。
因此,让我们首先了解当客户端启动模型训练作业时会发生什么。
客户端启动模型训练作业
模型训练作业开始于客户端首次向 H2O 发送模型训练请求。
以下序列图显示了当客户端发送模型训练请求时在 H2O 内部发生的交互序列:
图 4.7 – 模型训练请求中的交互序列
在模型训练请求期间发生以下一系列操作:
-
用户首先运行一个包含所有指令和函数调用的脚本,以向 H2O 发出模型训练请求。
-
脚本包含一个模型训练函数调用及其相应的参数。这还包括一个 H2O AutoML 函数调用,其操作方式类似。
-
函数调用指示相应的语言特定 H2O 客户端,该客户端创建一个包含所有正确训练模型所需参数信息的POST请求。
-
然后,H2O 客户端将执行一个curl操作,将 HTTP POST 请求发送到它所在的主机 IP 地址上的 H2O 网络服务器。
-
从这一点开始,信息流在 H2O 服务器内部执行。H2O 服务器根据用户选择的要训练的模型将请求派遣到适当的模型训练端点。
-
此模型训练端点从请求中提取参数值并安排一个作业。
-
一旦作业被安排,它就开始训练模型。
-
训练作业的
job_id
,可用于识别作业的进度。 -
作业管理器随后将
job_id
发送回训练作业,该作业将其分配给自己。 -
训练作业随后将相同的
job_id
返回给模型训练端点。 -
模型训练端点创建一个包含此
job_id
的 JSON 响应,并指示网络服务器将其作为响应发送给发出请求的客户端。 -
网络服务器相应地做出 HTTP 响应,通过网络传输并到达 H2O 客户端。
-
客户端随后创建一个包含此
job_id
的模型对象,用户可以使用它进一步跟踪模型训练的进度或在训练完成后进行预测。
这总结了当 H2O 服务器接收到模型训练请求时内部发生的事件序列。
现在我们已经了解了训练请求会发生什么,让我们了解在第 6 步中创建的训练作业在训练模型时发生的事件。
H2O 运行模型训练作业
在 H2O 中,模型的训练由一个内部模型训练作业执行,该作业独立于用户的 API 请求。用户的 API 请求只是启动作业;作业管理器执行实际的作业执行。
以下序列图显示了模型训练作业在训练模型时发生的交互序列:
图 4.8 – 模型训练作业执行中的交互序列
在模型训练期间发生以下一系列操作:
-
模型训练作业将模型训练分解为任务。
-
然后,作业将任务提交给执行框架。
-
执行框架使用 Java 并发库
jsr166y
通过 Fork/Join 处理框架以并发方式执行任务。 -
一旦分叉任务成功执行,执行库将发送回完成的任务结果。
-
一旦所有任务完成,训练好的模型将被发送回模型训练作业。
-
模型训练作业随后将模型对象存储在 H2O 的分布式键值存储中,并为其分配一个唯一的模型 ID。
-
训练作业随后通知作业管理器模型训练已完成,然后作业管理器可以自由地继续处理其他训练作业。
既然我们已经了解了模型训练作业在训练模型时幕后发生的事情,那么让我们继续了解当客户端轮询模型训练状态时会发生什么。
客户端轮询模型训练作业完成状态
如前所述,模型的实际训练是独立于客户端的训练请求处理的。在这种情况下,一旦客户端发送了训练请求,客户端实际上并不知道模型的进度。客户端需要不断轮询模型训练作业的状态。这可以通过手动使用 HTTP 发出请求或通过某些客户端软件功能来完成,例如进度跟踪器定期轮询 H2O 服务器以获取模型训练状态。
以下序列图展示了当客户端轮询模型训练作业完成情况时发生的交互序列:
图 4.9 – 用户轮询模型状态交互序列
当客户端轮询模型训练作业完成情况时,会发生以下一系列操作:
-
要获取模型训练的状态,客户端将发出
GET
请求,传递它在首次请求训练模型时收到的job_id
。 -
GET
请求通过网络传输到主机 IP 地址的 H2O 网络服务器。 -
H2O 网络服务器将请求调度到 H2O 作业端点。
-
H2O 作业端点随后将查询作业管理器,请求
GET
请求中传递的job_id
的状态。 -
作业管理器将返回相应
job_id
的作业信息,其中包含有关模型训练进度的信息。 -
H2O 作业端点将为
job_id
准备包含作业信息的 JSON 响应,并将其发送到 H2O 网络服务器。 -
H2O 网络服务器随后将 JSON 作为响应发送回发起请求的客户端。
-
接收到响应后,客户端将解包此 JSON 并根据作业信息更新用户关于模型训练状态的了解。
这总结了当客户端轮询模型训练状态时发生的各种交互。考虑到这一点,现在让我们看看当客户端在得知模型训练作业已完成模型训练后请求模型信息时会发生什么。
客户端查询模型信息
一旦模型训练成功,用户很可能会想要分析模型的详细信息。机器学习模型与其性能和质量相关联的元数据非常丰富。即使模型尚未用于预测,这些元数据也非常有用。但是,正如我们在上一节中看到的,模型训练过程与用户的请求无关,一旦训练完成,H2O 不会返回模型对象。然而,H2O 服务器确实提供了一个 API,使用它可以获取服务器上已存储的模型信息。
以下序列图显示了客户端请求有关已训练模型的信息时发生的交互序列:
图 4.10 – 用户查询模型信息
当客户端轮询模型训练作业完成时,会发生以下一系列操作:
-
要获取模型信息,客户端将发送一个
GET
请求,传递机器学习模型的唯一model_id
。 -
GET
请求通过网络传输到主机 IP 地址的 H2O 网络服务器。 -
H2O 网络服务器将请求调度到 H2O 模型端点。
-
当模型训练作业完成模型训练时,所有模型信息都存储在 H2O 的分布式键值存储中。H2O 模型端点将使用
model_id
作为过滤器查询这个分布式键值存储。 -
分布式键值存储将返回传递给它的
model_id
的所有模型信息。 -
然后,H2O 模型端点将准备一个包含模型信息的 JSON 响应,并将其发送到 H2O 网络服务器。
-
H2O 网络服务器将相应地将 JSON 作为响应发送回发起请求的客户端。
-
在收到响应后,客户端将提取所有模型信息并显示给用户。
一旦模型训练完成,它将直接存储在 H2O 服务器本身中,以便在有任何预测请求时快速访问。您还可以下载 H2O 模型;然而,任何未导入到 H2O 服务器的模型都不能用于预测。
这总结了 H2O 客户端-服务器通信中各个部分发生的整个交互序列。现在我们了解了 H2O 如何使用作业和作业管理器内部训练模型,让我们进一步深入,尝试理解当 H2O AutoML 训练和优化超参数,最终选择最佳模型时会发生什么。
理解 H2O AutoML 如何执行超参数优化和训练
在本书的整个过程中,我们惊叹于 AutoML 过程如何自动化训练和选择最佳模型这一复杂的任务,而无需我们动手。然而,在每一次自动化背后,都有一系列简单的步骤,这些步骤以顺序的方式执行。
现在我们已经对 H2O 的架构以及如何使用 H2O AutoML 来训练模型有了很好的理解,我们现在终于可以打开黑盒,即 H2O AutoML。在本节中,我们将了解 H2O AutoML 在幕后做了什么,以便它能够自动化整个训练和选择最佳机器学习模型的过程。
这个问题的答案相当简单。H2O AutoML 通过使用网格搜索超参数优化自动完成整个机器学习过程。
网格搜索超参数优化对于许多非专业人士来说听起来非常令人畏惧,但如果你了解一些模型训练的基本概念,特别是超参数的重要性,这个概念本身实际上是非常容易理解的。
因此,在我们深入探讨网格搜索超参数优化之前,让我们首先了解什么是超参数。
理解超参数
大多数软件工程师都知道什么是参数:包含某些用户输入数据或任何系统计算数据,这些数据被馈送到另一个函数或过程中的某些变量。然而,在机器学习中,由于超参数的引入,这个概念稍微复杂一些。在机器学习领域,有两种类型的参数。一种我们称之为模型参数,或简称参数,另一种是超参数。尽管它们的名称相似,但它们之间有一些重要的区别,所有在机器学习领域工作的软件工程师都应该记住。
那么,让我们通过简单的定义来理解它们:
-
模型参数:模型参数是机器学习算法在模型训练过程中从给定数据集中计算或学习到的参数值。一些基本的模型参数示例包括数据集中的均值或标准差、权重和偏差。这些是我们从训练数据中学习到的元素,这些是我们机器学习算法用来训练机器学习模型的参数值。模型参数也称为内部参数。在给定的机器学习训练场景中,模型参数是不可调整的。
-
超参数:超参数是模型训练之外的外部配置,不是从训练数据集中派生出来的。这些是由机器学习实践者设置的参数值,用于推导模型参数。它们是机器学习实践者通过启发式方法发现并输入到模型训练开始之前的值。一些简单的超参数例子包括随机森林中的树的数量,或者回归算法中的学习率。每种机器学习算法都将有其自己所需的一组超参数。超参数是可调整的,并且通常在给定的机器学习训练场景中通过实验来获得最优模型。
训练最优模型的目标很简单:
-
你选择最佳的超参数组合。
-
这些超参数生成理想的模型参数。
-
这些模型参数训练出一个错误率最低的模型。
听起来很简单。然而,这里有一个问题。超参数在本质上并不直观。人们不能仅仅观察数据并决定超参数的x值将给我们带来最佳模型。找到完美的超参数是一个试错过程,其目的是找到最小化错误的一个组合。
现在,接下来出现的问题是,你如何找到训练模型的最佳超参数。这就是超参数优化出现的地方,我们将在下一章中介绍。
理解超参数优化
超参数优化,也称为超参数调整,是指为给定的机器学习算法选择最佳超参数集的过程,以训练出最优模型。这些值的最佳组合可以最小化机器学习算法预定义的损失函数。简单来说,损失函数是一个衡量某些错误单位的函数。不同的机器学习算法有不同的损失函数。在潜在的超参数值组合中,具有最低错误量的模型被称为具有最优超参数。
实现超参数优化有许多方法。其中一些最常见的方法是网格搜索、随机网格搜索、贝叶斯优化和基于梯度的优化。每个都是一个非常广泛的话题;然而,对于本章,我们将只关注两种方法:网格搜索和随机网格搜索。
小贴士
如果你想了解更多关于超参数调整的贝叶斯优化技术,那么请随意探索。你可以在以下链接中找到有关此主题的更多信息:arxiv.org/abs/1807.02811
。同样,你可以在以下链接中找到更多关于基于梯度的优化的详细信息:arxiv.org/abs/1502.03492
。
实际上,H2O 的 AutoML 用于超参数优化的方法是随机网格搜索方法,但你需要理解优化中的原始网格搜索方法,以便理解随机网格搜索。
因此,让我们从网格搜索超参数优化开始。
理解网格搜索优化
让我们以我们在第一章中使用的例子,即理解 H2O AutoML 基础为例。在这个数据集中,我们正在训练一个模型,该模型通过学习花瓣宽度、花瓣长度、萼片宽度和萼片长度来预测花的分类类型。
现在,你面临的首要问题是:应该使用哪种机器学习算法来训练模型?假设你确实找到了答案并选择了一个算法,那么接下来的问题将是:哪个超参数组合将给我带来最优的模型?
传统上,机器学习从业者会为给定的机器学习算法训练多个模型,这些模型使用不同的超参数值组合。然后,他们会比较这些模型的性能,找出哪个超参数组合训练出的模型具有最低的可能错误率。
下面的图表展示了不同的超参数组合如何训练出性能各异的模型:
图 4.11 – 手动超参数调整
让我们以你正在训练决策树为例。它的超参数是树的数量ntrees
和最大深度max_depth
。如果你正在进行手动搜索以进行超参数优化,那么你将最初从ntrees
的值50
、100
、150
和200
以及max_depth
的值5
、10
和50
开始,训练模型并测量它们的性能。当你发现哪个值的组合给你带来最佳结果时,你将这些值设置为阈值,并通过较小的增量或减量调整它们,使用这些新的超参数值重新训练模型,并再次比较性能。你一直这样做,直到找到最佳的超参数值组合,以获得最佳性能。
然而,这种方法有几个缺点。首先,你可以尝试的值范围有限,因为你只能手动训练这么多模型。所以,如果你有一个值介于 1 到 10,000 之间的超参数,那么你需要确保你覆盖足够的范围,以免因为巨大的误差而错过理想值。如果你这样做,那么你将不断以较小的增量或减量调整值,花费大量时间进行优化。其次,随着超参数数量的增加以及你想要使用的可能值和值组合数量的增加,机器学习从业者管理并运行优化过程变得繁琐。
为了管理和部分自动化使用不同超参数训练多个模型的过程,发明了网格搜索。网格搜索也被称为笛卡尔超参数搜索或穷举搜索。
网格搜索基本上将给定超参数的所有值映射到笛卡尔网格上,并在网格中全面搜索组合以训练模型。参考以下图表,它展示了超参数网格搜索如何转化为训练多个模型:
图 4.12 – 卡尔丹网格搜索超参数调整
在图中,我们可以看到我们有一个二维网格,它映射了两个超参数。使用这个笛卡尔网格,我们可以进一步将超参数值的组合扩展到每个参数 10 个值,从而扩展我们的搜索。网格搜索方法会全面搜索两个超参数的不同值。因此,它将有 100 种不同的组合,总共训练 100 个不同的模型,所有这些模型都是在不需要太多手动干预的情况下训练的。
H2O 确实具有网格搜索功能,用户可以使用它来测试他们自己手动实现的网格搜索方法进行超参数优化。当使用网格搜索训练模型时,H2O 会将所有训练的模型映射到网格中相应的超参数值组合。H2O 还允许你根据任何支持的模型性能指标对所有这些模型进行排序。这种排序可以帮助你根据指标值快速找到性能最佳的模型。我们将在第六章中进一步探讨性能指标,理解 H2O AutoML 排行榜和其他性能指标。
然而,尽管自动化并引入了提高生活质量的改进,这种方法仍然存在一些缺点。网格搜索超参数优化受到所谓的维度诅咒的影响。
维度诅咒这个术语是由理查德·E·贝尔曼在考虑动态规划问题时提出的。从机器学习的角度来看,这个概念表明,随着超参数组合数量的增加,网格搜索将执行的评估数量将以指数级增长。
例如,假设你有一个超参数x,并且你想尝试 1 到 20 的整数值。在这种情况下,你将进行 20 次评估,换句话说,训练 20 个模型。现在假设还有一个超参数y,并且你想尝试与x的值相结合的 1 到 20 的值。你的组合将如下所示:
(1,1), (1,2), (1,3), (1,4), (1,5), (1,6), (1,7)……(20,20),其中(x, y)
现在,你的网格中共有 20x20=400 种组合,你的网格搜索优化将最终训练 400 个模型。再添加一个超参数z,你的组合数量将激增,超出管理范围。你拥有的超参数越多,你尝试的组合就越多,组合爆炸现象就越严重。
考虑到机器学习对时间和资源敏感,穷举搜索对于找到最佳模型来说是没有效果的。现实世界有局限性,因此随机选择超参数值已被证明往往比穷举网格搜索提供更好的结果。
这将我们引向超参数优化的下一个方法,即随机网格搜索。
理解随机网格搜索优化
随机网格搜索通过从超参数搜索空间中选择随机值来替代之前的穷举网格搜索,而不是按顺序耗尽所有值。
例如,参考以下图表,它展示了随机网格搜索优化的一个示例:
图 4.13 – 随机网格搜索超参数调整
上述图表是两个超参数X和Y的 100 种组合的超参数空间。随机网格搜索优化将随机选择其中几个,并使用这些超参数值进行评估。
随机网格搜索优化的缺点是它是一种在有限评估次数内寻找最佳超参数值组合的最佳努力方法。它可能或可能不会找到训练最佳模型的最佳超参数值组合,但给定一个大的样本量,它可以找到接近完美的组合来训练一个质量足够好的模型。
H2O 库函数支持随机网格搜索优化。它为用户提供设置自己的超参数搜索网格和设置搜索标准参数以控制搜索类型和范围的功能。搜索标准可以是任何东西,例如最大运行时间、最大训练模型数量或任何指标。H2O 将随机无重复地从网格中选择不同的超参数组合进行评估,并持续搜索和评估,直到满足搜索标准。
H2O AutoML 的工作方式与随机网格搜索优化略有不同。它不是等待用户输入超参数搜索网格,而是通过已经有一个包含所有潜在值的超参数列表,并在网格中默认值的形式自动完成这一部分。H2O AutoML 还提供了将用户设置的超参数搜索列表中的非默认值包括在内的功能。H2O AutoML 已经为算法预设了值;我们将在下一章中探讨这些值,同时了解不同算法的工作原理。
摘要
在本章中,我们了解了 H2O 的高级架构以及构成整体架构的不同层级。然后,我们深入到架构的客户端和 JVM 层,了解了构成 H2O 软件堆栈的不同组件。接下来,在心中牢记 H2O 的架构,我们了解了客户端和服务器之间发生的交互流程,了解了我们如何确切地命令 H2O 服务器执行各种机器学习活动。我们还了解了在模型训练过程中,交互如何在架构堆栈中流动。
建立在现有知识的基础上,我们研究了在模型训练过程中 H2O 服务器内部发生的交互序列。我们还探讨了 H2O 如何使用作业管理器来协调训练作业,以及 H2O 如何与用户沟通模型训练的状态。最后,我们揭开了 H2O AutoML 的面纱,并了解了它是如何自动训练最佳模型的。我们已经理解了超参数优化的概念及其各种方法,以及 H2O 如何自动化这些方法并减轻它们的缺点以自动训练最佳模型。
现在我们已经了解了 H2O AutoML 的内部细节以及它是如何训练模型的,我们现在准备了解 H2O AutoML 训练的各种机器学习算法以及它们如何进行预测。在下一章中,我们将探索这些算法,并更好地理解模型,这将帮助我们证明哪种模型最适合给定的机器学习问题。
第五章:理解 AutoML 算法
所有机器学习算法都以计算统计学为基础。计算统计学是统计学与计算机科学的结合,其中计算机用于计算复杂的数学。这种计算就是机器学习算法,而我们从中得到的预测结果。作为机器学习领域的工程师和科学家,我们通常需要了解机器学习算法的基本逻辑。人工智能领域有大量的机器学习算法。它们都旨在解决不同类型的预测问题。它们各自也有自己的优缺点。因此,工程师和科学家的工作就是找到能够解决给定预测问题且在所需约束条件下表现最佳的机器学习算法。然而,随着 AutoML 的发明,这项工作变得容易多了。
尽管 AutoML 承担了寻找最佳机器学习算法的巨大责任,但作为工程师和科学家,我们仍然需要验证和证明这些算法的选择。为此,对机器学习算法的基本理解是必不可少的。
在本章中,我们将探讨和理解 H2O AutoML 用于训练模型的各种机器学习算法。如前所述,所有机器学习算法都有深厚的统计学基础。统计学本身是数学的一个庞大分支,内容太多,无法在一章中涵盖。因此,为了对机器学习算法的工作原理有一个基本的理解,我们将从基本统计学概念出发,从概念上探讨它们的内部运作,而不是深入数学。
小贴士
如果你想要在统计学领域获得更多知识,那么以下链接应该是一个不错的起点:online.stanford.edu/courses/xfds110-introduction-statistics
。
首先,我们将了解不同类型的机器学习算法,然后学习这些算法的工作原理。我们将通过将它们分解为单个概念,理解它们,然后再将这些概念组合起来以理解整体来做到这一点。
本章将涵盖以下主题:
-
理解不同类型的机器学习算法
-
理解广义线性模型算法
-
理解分布式随机森林算法
-
理解梯度提升机算法
-
理解深度学习是什么
因此,让我们从理解不同类型的机器学习算法开始我们的旅程。
理解不同类型的机器学习算法
机器学习算法旨在解决特定的预测问题。这些预测问题可以是任何在预测准确的情况下能提供价值的问题。不同预测问题之间的区别在于要预测的价值是什么。是简单的“是”或“否”值,一个数值范围,还是从潜在值列表中选择的一个特定值,或者是文本的概率或语义?机器学习领域足够广泛,可以以多种方式涵盖大多数,如果不是所有这样的问题。
因此,让我们从了解预测问题的不同类别开始。它们如下:
- 回归:回归分析是一种统计过程,旨在找到独立变量(也称为特征)和因变量(也称为标签或响应变量)之间的关系,并使用这种关系来预测未来的值。
回归问题是指旨在预测某些连续数值的问题——例如,根据汽车的品牌名称、发动机大小、经济性和电子特性来预测汽车的价格。在这种情况下,汽车的品牌名称、发动机大小、经济性和电子特性是独立变量,因为它们的存在与其他值无关,而汽车价格是因变量,其值取决于其他特性。此外,汽车的价格是一个连续值,因为它可以在 0 到 1 亿美元或任何其他货币的数值范围内。
- 分类:分类是一种统计过程,旨在根据标签值与特征之间的关系将它们分类到某些类别或类别中。
分类问题是指旨在预测一组特定值的问题——例如,根据一个人的胆固醇水平、体重、锻炼水平、心率和家庭病史来预测这个人是否可能面临心脏病。另一个例子是预测餐厅在谷歌评论上的评分,评分范围从 1 到 5 星,这取决于位置、食物、环境和价格。
如您从这些例子中看到的,分类问题可以是“是”或“否”,“真”或“假”,“1”或“0”类型的分类,或者是一组特定的分类值,例如在谷歌评论示例中,值可以是 1、2、3、4 或 5。因此,分类问题可以进一步分为以下几类:
-
二元分类:在这种分类问题中,预测值是二元的,这意味着它们只有两个值——也就是说,“是”或“否”,“真”或“假”,“1”或“0”。
-
多类/多项式分类:在这种分类问题中,预测值是非二元的,也称为多项式,这意味着它们有多于两组的值。例如,按年龄分类,涉及从 1 到 100 的整数,或者按基本颜色分类,可以是红色、黄色或蓝色。
-
聚类:聚类是一种统计过程,旨在以某种方式将某些数据点分组或划分,使得单个组内的数据点具有与其他组数据点不同的相似特征。
聚类问题:聚类问题是旨在理解一组值内部相似性的问题。
例如,给定一组具有某些细节(如他们使用的硬件、他们玩的不同游戏以及他们玩这些视频游戏的时间)玩视频游戏的人,你可以根据他们最喜欢的游戏类型对人们进行分类。聚类可以进一步细分为以下几种:
-
硬聚类:在这种类型的聚类中,所有数据点要么属于一个簇,要么属于另一个簇;它们是互斥的。
-
软聚类:在这种类型的聚类中,不是将数据点分配给一个簇,而是计算数据点可能属于某个簇的概率。这增加了数据点可能同时属于多个簇的可能性。
-
关联:关联是一种统计过程,旨在找出如果事件 A 发生了,事件 B 发生的可能性有多大?关联问题基于关联规则,这些规则是如果-那么陈述,显示了不同数据点之间关系的概率。
关联问题的最常见例子是市场篮子分析。市场篮子分析是一个预测问题,给定一个用户在市场上购买了一定产品 A,那么用户购买与产品 A 相关的产品 B 的概率是多少?
- 优化/控制:控制理论、最优控制理论或优化问题是数学的一个分支,它处理寻找一组值的组合,以优化动态系统。机器学习控制(MLC)是机器学习中的一个子领域,旨在使用机器学习来解决优化问题。MLC 的一个好例子是将机器学习应用于优化道路上的交通,使用自动汽车。
现在我们已经了解了不同类型的预测问题,让我们深入了解不同类型的机器学习算法。不同类型的机器学习算法被分类如下:
- 监督学习:监督学习是根据先前存在的、已标记的值来映射自变量和因变量之间关系的机器学习任务。标记数据是包含有关其特征哪些是依赖的、哪些是独立的的信息的数据。在监督学习中,我们知道我们想要预测的特征,并将该特征标记为标签。机器学习算法将使用这些信息来映射关系。使用这种映射,我们预测新输入值的输出。另一种理解这个问题的方式是,先前存在的值监督机器学习算法的学习任务。
监督学习算法通常用于解决回归和分类问题。
监督学习算法的一些例子包括决策树、线性回归和神经网络。
- 无监督学习:如前所述,监督学习是从未标记的数据中寻找模式和行为的机器学习任务。在这种情况下,我们不知道我们想要预测哪个特征,或者我们想要预测的特征甚至可能不是数据集的一部分。无监督学习帮助我们预测潜在的重复模式,并使用这些模式对数据集进行分类。另一种理解这个问题的方式是,没有标记的值来监督机器学习算法的学习任务;算法独立地学习模式和行为了。
无监督学习算法通常用于解决聚类和关联问题。
无监督学习算法的一些例子包括K-means 聚类和关联规则学习。
- 半监督学习:半监督学习介于监督学习和无监督学习之间。它是执行部分标记数据集上的机器学习任务的机器学习任务。它用于你有一个小部分标记的数据集和大量未标记数据集的场景。在现实场景中,标记大量数据是一个昂贵的任务,因为它需要大量的实验和需要人工解释的上下文信息,而未标记数据相对容易获取。在这种情况下,半监督学习通常证明是有效的,因为它擅长从未标记数据集中假设预期的标签值,同时像任何监督学习算法一样高效地工作。
无监督学习算法通常用于解决聚类和分类问题。
半监督学习算法的一些例子包括生成模型和拉普拉斯正则化。
- 强化学习:强化学习是一个旨在在给定环境中识别下一步正确逻辑动作以最大化累积奖励的机器学习任务。在这种学习中,预测的准确性是在使用正强化和/或负强化后计算的,这些强化再次被输入到算法中。这种对环境的持续学习最终帮助算法找到最佳步骤序列以最大化奖励,从而做出最准确的决策。
强化学习通常用于解决回归、分类和优化问题的混合。
强化学习算法的一些例子包括蒙特卡洛方法、Q 学习和深度 Q 网络。
尽管 AutoML 技术已经足够成熟,可以用于商业用途,但与机器学习领域的广泛发展相比,它仍然处于起步阶段。AutoML 可能能够在最短的时间内使用最少或没有人为干预来训练最佳的预测模型,但它的潜力目前仅限于监督学习。以下图表总结了不同机器学习任务下分类的各种机器学习算法:
图 5.1 – 机器学习问题的类型和算法
同样,H2O 的 AutoML 也专注于监督学习,因此你通常需要提供标签数据来供其使用。
与监督学习算法相比,执行无监督学习的机器学习算法通常更为复杂。因为在这种情况下,没有真实数据来衡量模型的性能。这与 AutoML 的本质相悖,AutoML 非常依赖于模型性能的测量来自动化训练和超参数调整。
因此,相应地,H2O AutoML 属于监督机器学习算法的范畴,它训练多个监督机器学习算法来解决回归和分类问题,并根据它们的性能进行排名。在本章中,我们将关注这些机器学习算法,了解它们的功能,以便我们能够充分理解、选择和证明 H2O AutoML 为特定预测问题训练的不同模型。
基于这种理解,让我们从第一个机器学习算法:广义线性模型开始。
理解广义线性模型算法
广义线性模型(GLM),正如其名所示,是一种灵活的推广线性模型的方法。它是由约翰·尼尔和罗伯特·韦德伯恩提出的,作为一种将各种回归模型组合成一个分析的方法,同时考虑到不同的概率分布。你可以在rss.onlinelibrary.wiley.com/doi/abs/10.2307/2344614
找到他们详细的论文(Nelder, J.A. and Wedderburn, R.W., 1972. 广义线性模型. 皇家统计学会会刊:A 系列(一般),135(3),pp.370-384)。
现在,你可能想知道什么是线性模型。为什么我们需要对它们进行推广?它提供了什么好处?这些问题确实很重要,而且不需要深入数学知识就可以很容易地理解。一旦我们分解了逻辑,你会发现广义线性模型的概念非常容易理解。
那么,让我们先从理解线性回归的基本概念开始。
线性回归简介
线性回归可能是最古老的统计模型之一,其历史可以追溯到 200 年前。它是一种在图上线性映射因变量和自变量之间关系的方法。这意味着两个变量之间的关系可以完全由一条直线来解释。
考虑以下例子:
图 5.2 – 线性回归
这个例子展示了两个变量之间的关系。一个人的身高 H 是自变量,而一个人的体重 W 是因变量。这两个变量之间的关系可以很容易地用一条红色的直线来解释。一个人越高,他或她的体重越有可能更重。这很容易理解。
统计上,任何直线的通用方程,也称为线性方程,如下所示:
在这里,我们有以下内容:
-
y 是 Y 轴上的一个点,表示因变量。
-
x 是 X 轴上的一个点,表示自变量。
-
b**1 是直线的斜率,也称为梯度,表示直线的陡峭程度。梯度越大,直线越陡。
-
b**0 是一个常数,表示直线与 Y 轴相交的点。
在线性回归过程中,机器将在图上映射两个变量的所有数据点,并在图上随机放置直线。然后,它将通过将图中的数据点的 x 值插入线性方程中来计算 y 的值,并将结果与数据点的相应 y 值进行比较。之后,它将计算它计算的 y 值与实际 y 值之间的误差大小。这种值之间的差异就是我们所说的残差。
以下图表应有助于你理解什么是残差:
图 5.3 – 线性回归中的残差
机器将为所有数据点做这件事,并记录所有误差。然后,它将通过改变 b1 和 b0 的值来尝试调整直线,这意味着改变图上直线的角度和位置,并重复这个过程。它将这样做,直到最小化误差。
产生最少误差的 b1 和 b0 的值是两个变量之间最准确的线性关系。具有这些 b1 和 b0 值的方程是线性模型。
现在,假设你想预测一个身高 180 厘米的人的体重。然后,你使用这个相同的线性模型方程,使用 b1 和 b0 的值,将 x 设置为 180,并计算 y,这将是你预期的体重。
恭喜你,你刚刚在心中进行了机器学习,没有任何计算机的帮助,并且做出了预测!实际的机器学习工作方式相同,尽管增加了复杂算法的复杂性。线性回归不仅限于两个变量——它还可以处理存在多个自变量的多个变量。这种线性回归称为多元或曲线回归。这种线性回归的方程如下扩展:
在这个方程中,附加的变量——x1、x2、x3 等等——分别与它们自己的系数——b1、b2 和 b3 相加。
如果你对线性回归的内部工作原理感兴趣,不妨探索这些算法及其背后的数学。
理解线性回归的假设
当在给定的数据集上训练模型时,线性回归基于对数据的某些假设。这些假设之一是误差的正态性。
在我们了解误差的正态性之前,让我们快速了解概率密度函数的概念。这是一个数学表达式,它定义了离散值的概率分布——换句话说,它是一个数学表达式,显示了从给定的样本空间中发生样本值的概率。为了理解这一点,请参考以下图表:
图 5.4 – 两个骰子数值的概率分布
前面的图表显示了当公平且独立地掷一对六面骰子时,所有可能出现的数值的概率分布。存在不同类型的分布。以下是一些常见分布的例子:
图 5.5 – 不同类型的分布
误差的正态性表明,数据残差必须是正态分布的。正态分布,也称为高斯分布,是一个关于均值对称的概率密度函数,其中最接近均值的值出现频率较高,而远离均值的值很少出现。以下图表显示了正态分布:
图 5.6 – 正态分布
线性回归期望计算出的残差落在正态分布范围内。在我们之前的关于预期体重与一定身高的人实际体重之间误差的例子中,预测体重和实际体重之间必然存在一些误差。然而,由于预期体重和预测体重之间极端差异的人出现的次数不会太多,因此预测的残差或误差很可能会落在正态分布范围内。
考虑一个人们申请健康保险赔付的场景。以下图表显示了该数据集的线性回归图样本:
图 5.7 – 健康保险赔付
在前面的图中,你可以看到来自各个年龄段的大多数人没有申请健康保险。其中一些人申请了,索赔费用差异很大。有些人有轻微的问题,花费很少,而有些人遭受了严重的伤害,不得不进行昂贵的手术。
如果你通过这个数据集绘制线性回归线,它看起来如下所示:
图 5.8 – 健康保险赔付的线性回归
但是,现在如果你从所有数据点的预期值和预测值中计算残差误差,那么这些残差的概率分布将不会落入正态分布。它看起来如下所示:
图 5.9 – 健康保险赔付的残差分布
这是一个不精确的模型,因为预期值和预测值甚至不够接近,以至于可以四舍五入或纠正。那么,对于这种错误假设对于数据集不成立的情况,你该怎么办?如果残差的分布是泊松分布而不是正态分布,机器将如何纠正?
好吧,这个问题的答案是残差的分布取决于数据集本身的分布。如果因变量的值呈正态分布,那么残差的分布也将是正态的。因此,一旦我们确定了哪个概率密度函数适合数据集,我们就可以使用该函数来训练我们的线性模型。
根据这个函数,为每个概率密度函数有专门的线性回归方法。如果你的分布是泊松,那么你可以使用泊松回归。如果你的数据分布是负二项式,那么你可以使用负二项式回归。
使用广义线性模型(GLM)进行工作
现在我们已经涵盖了基础知识,让我们来了解什么是 GLM。GLM 是一种指向所有特定于数据类型概率分布的回归方法的方式。技术上讲,所有回归模型都是 GLM,包括我们的普通简单线性模型。GLM 只是将它们封装在一起,并根据概率分布函数训练适当的回归模型。
GLM 的工作方式是使用所谓的连接函数,结合系统成分和随机变量。
这些是广义线性模型(GLM)的三个组成部分:
- 系统成分:回到多元线性方程,我们有以下内容:
在这里,b1x1+ b2x2 + b3x3 + …… + b0 是系统成分。这是将我们的数据(也称为预测变量)与我们的预测相联系的功能。
-
随机成分:这个成分指的是响应变量的概率分布。这将是响应变量是正态分布、二项分布还是其他任何形式的分布。
-
链接函数:链接函数是一个将数据的非线性关系映射到线性关系上的函数。换句话说,它弯曲线性回归的线,以更准确地表示非线性数据的关系。它是随机成分和系统成分之间的链接。我们可以用链接函数数学上解释方程式为 Y = fn( b1x1+ b2x2 + b3x3 + …… + b0 ),其中 fn 是随响应变量分布变化的链接函数。
链接函数对于不同的分布是不同的。下表显示了不同分布的不同链接函数:
分布类型 | 链接函数 | 算法名称 |
---|---|---|
正态 | ![]() |
线性模型 |
二项分布 | ![]() |
逻辑回归 |
泊松 | ![]() |
泊松回归 |
伽马 | ![]() |
伽马回归 |
图 5.10 – 不同分布类型的链接函数
当训练 GLM 模型时,你可以选择家庭超参数的值。家庭选项指定了响应列的概率分布,GLM 训练算法在训练期间使用适当的链接函数。
家庭超参数的值如下:
-
高斯分布:如果响应是一个实整数,你应该选择此选项。
-
二项分布:如果响应是具有两个类别的分类响应或二进制,可以是枚举或整数,你应该选择此选项。
-
分数二项分布:如果响应是介于 0 和 1 之间的数值,你应该选择此选项。
-
有序:如果响应是一个具有三个或更多类别的分类响应,你应该选择此选项。
-
准二项分布:如果响应是数值,你应该选择此选项。
-
多项式分布:如果响应是一个具有三个或更多类别的分类响应,且这些类别为枚举类型,你应该选择此选项。
-
泊松:如果响应是数值且包含非负整数,你应该选择此选项。
-
伽马分布:如果响应是数值且连续,并包含正实整数,你应该选择此选项。
-
Tweedie:如果响应是数值且包含连续的实数和非负值,你应该选择此选项。
-
负二项分布:如果响应是数值且包含非负整数,你应该选择此选项。
-
AUTO:这会自动为用户确定家族。
如你所猜,H2O 的 AutoML 在训练 GLM 模型时将 AUTO 选为家族类型。AutoML 过程通过理解数据集中响应变量的分布并应用正确的链接函数来训练 GLM 模型,来处理选择正确分布家族的情况。
恭喜,我们刚刚了解了 GLM 算法的工作原理!GLM 是一个非常强大且灵活的算法,H2O AutoML 专家地配置了其训练,以便训练最准确和性能最高的 GLM 模型。
现在,让我们继续了解 H2O 训练的下一个机器学习算法:分布式随机森林(DRF)。
理解分布式随机森林算法
DRF,简称为随机森林,是一种非常强大的监督学习技术,常用于分类和回归。DRF 学习技术的基础是基于决策树,其中随机创建大量决策树用于预测,并将它们的预测结果结合起来得到最终输出。这种随机性用于最小化所有单个决策树的偏差和方差。所有决策树共同组合在一起,称为森林,因此得名随机森林。
要对 DRF 有更深入的概念理解,我们需要了解 DRF 的基本构建块——那就是决策树。
决策树简介
用非常简单的话来说,决策树只是一组IF条件,根据传递给它的数据返回是或否的答案。以下图展示了决策树的一个简单示例:
图 5.11 – 简单决策树
上一图展示了基本的决策树。决策树由以下组件组成:
-
节点:节点基本上是IF条件,根据条件是否满足来分割决策树。
-
根节点:决策树顶部的节点被称为根节点。
-
叶节点:决策树中不再分支的节点被称为叶节点,或简称为叶子。在这种情况下,条件是如果传递给它的数据值是数值型的,则答案是数据是一个数字;如果传递给它的数据不是数值型的,则答案是数据是非数值型。这很简单,容易理解。
如图 5.11 所示,决策树基于一个简单的真或假问题。决策树也可以基于数值数据的数学条件。以下示例展示了基于数值条件的决策树:
图 5.12 – 数值决策树
在这个例子中,根节点计算智商数是否大于 300,并决定它是人工智能还是人类智能。
决策树也可以组合使用。它们可以形成依赖于先前决策结果的复杂决策条件集。请参考以下示例中的复杂决策树:
图 5.13 – 复杂决策树
在前面的例子中,我们试图计算你是否可以“出去玩”或“完成你的机器学习研究”。这个决策树结合了数值数据和数据的分类。在做出预测时,决策树将从顶部开始,逐层向下,根据数据是否满足条件做出决策。叶节点是决策树最终的潜在结果。
在这个知识的基础上,让我们在一个示例数据集上创建一个决策树。请参考以下表格中的示例数据集:
图 5.14 – 创建决策树的示例数据集
上述数据集的内容如下:
-
胸痛:此列表示患者是否患有胸痛。
-
良好血液循环:此列表示患者是否有良好的血液循环。
-
阻塞动脉:此列表示患者是否有阻塞的动脉。
-
心脏病:此列表示患者是否患有心脏病。
对于这个场景,我们想要创建一个决策树,该决策树使用胸痛、良好血液循环和阻塞动脉特征来预测患者是否患有心脏病。现在,在形成决策树时,我们首先需要做的是找到根节点。那么,我们应该将哪个特征放在决策树的顶部?
我们首先来看一下,仅凭“胸痛”特征在预测心脏病方面的表现。我们将遍历数据集中的所有值,并将它们映射到这个决策树上,同时比较“胸痛”列的值与心脏病列的值。我们将在决策树中跟踪这些关系。以“胸痛”为根节点的决策树如下:
图 5.15 – 胸痛特征的决策树
现在,我们对数据集中的其他所有特征都进行同样的操作。我们为“良好血液循环”创建一个决策树,并查看它在预测心脏病时的表现,同时记录比较结果,重复同样的过程来跟踪“动脉阻塞”状态。如果数据集中有任何缺失值,则跳过它们。理想情况下,你不应该使用包含缺失值的数据集。我们可以使用我们在第三章,“理解数据处理”中学到的技术,其中我们插补和处理缺失数据集值。
参考以下图表,它显示了创建的两个决策树 – 一个用于患者有阻塞的动脉,另一个用于患者有良好的血液循环:
图 5.16 – 阻塞性动脉和良好血液循环特征的决策树
现在我们已经为数据集中的所有特征创建了一个决策树,我们可以比较它们的结果以找到纯度最高的特征。在决策树的情况下,如果一个节点被平均分割,即 50/50,则称一个特征为 100% 不纯,如果所有数据都属于单个类别,则称其为 100% 纯。在我们的场景中,我们没有 100% 纯的特征。所有特征都有一定程度的不纯。因此,我们需要找到一种方法来找到最纯的特征。为此,我们需要一个可以衡量决策树纯度的指标。
数据科学家和工程师有很多种方法来衡量纯度。在决策树中衡量不纯度最常用的指标是Gini 不纯度。Gini 不纯度是衡量新随机数据实例在分类过程中被错误分类的可能性的度量。
Gini 不纯度的计算如下:
在这里,p1, p2, p3, p4…是心脏病各种分类的概率。在我们的场景中,我们只有两种分类 – 要或不要。因此,在我们的场景中,不纯度的度量如下:
因此,让我们计算我们刚刚创建的所有决策树的 Gini 不纯度,以便我们可以找到最纯的特征。具有多个叶子节点的决策树的 Gini 不纯度是通过计算单个叶子节点的 Gini 不纯度,然后计算所有不纯度值的加权平均来得到整个决策树的 Gini 不纯度。因此,让我们首先计算胸痛决策树的左叶子节点的 Gini 不纯度,并重复此操作以计算右叶子节点:
我们计算 Gini 不纯度的加权平均的原因是因为数据在决策树的两个分支中的表示并不是平均分配的。加权平均帮助我们抵消这种数据值的不均匀分布。因此,我们可以按照以下方式计算整个胸痛决策树的 Gini 不纯度:
Gini 不纯度 (胸痛) = 叶子节点的 Gini 不纯度的加权平均
Gini 不纯度 (胸痛) =
(左叶子节点中的数据输入总数 / 总行数) x 左叶子节点的 Gini 不纯度
+
(右叶子节点中的数据输入总数 / 总行数) x 右叶子节点的 Gini 不纯度
= (144 / (144 + 159)) x 0.395 + (159 / (144 + 159)) x 0.364
= 0.364
胸痛决策树的基尼不纯度为 0.364。
我们同样对其他特征决策树重复这个过程。我们应该得到以下结果:
-
胸痛决策树的基尼不纯度为 0.364
-
良好血液循环树的基尼不纯度为 0.360
-
阻塞动脉树的基尼不纯度为 0.381
比较这些值,我们可以推断出良好血液循环特征的基尼不纯度最低,使其成为数据集中最纯净的特征。因此,我们将用它作为决策树的根。
参考图 5.12和图 5.13,当我们使用良好血液循环特征对患者进行划分时,我们在左右叶节点上留下了一个不纯的结果分布。因此,每个叶节点都有显示有和无心脏病的结果混合。现在,我们需要找出一种方法,使用剩余的特征(胸痛和阻塞动脉)从良好血液循环特征中分离出结果混合。
因此,就像我们之前做的那样,我们将使用这些混合结果,并使用其他特征将它们分开,计算这些特征的基尼不纯度值。我们将选择最纯净的特征,并在给定的节点上进行替换以进行进一步分类。
我们同样需要为右分支重复这个过程。为了简化决策树节点的选择,我们必须做以下事情:
-
使用混合结果计算该节点所有剩余特征的基尼不纯度得分。
-
选择不纯度最低的一个,并用它替换节点。
-
在决策树的其余部分使用剩余特征重复相同的过程。
-
继续替换节点,只要分类降低了基尼不纯度,否则将其保留为叶节点。
因此,你的最终决策树将如下所示:
图 5.17 – 最终决策树
这个决策树适用于对真假值进行分类。如果你有数值数据会怎样呢?
使用数值数据创建决策树非常容易,几乎与我们对真假数据的处理步骤相同。以“重量”作为一个新特征;重量列的数据如下:
图 5.18 – 包含新特征“重量”,单位为千克的样本数据
对于这个场景,我们必须遵循以下步骤:
-
按升序排序数据。在我们的场景中,我们将按重量列从高到低对数据集的行进行排序。
-
计算所有相邻行的平均重量:
图 5.19 – 计算后续行值的平均值
- 计算我们计算的所有平均值的基尼不纯度:
图 5.20 - 计算所有平均值的 Gini 不纯度
-
识别并选择给我们带来最小 Gini 不纯度值的平均特征值。
-
使用所选特征值作为决策树中的决策节点。
使用决策树进行预测非常简单。你将有一组具有胸痛、阻塞的动脉、良好的循环和体重等值的数值数据,并将这些数据输入到决策树模型中。模型将根据节点条件过滤决策树中的值,最终到达具有预测值的叶节点。
恭喜你——你刚刚理解了决策树的概念!尽管决策树易于理解和实现,但它们在解决现实生活中的机器学习问题方面并不出色。
使用决策树存在某些缺点:
-
决策树非常不稳定。数据集的任何微小变化都会极大地改变模型的性能和预测结果。
-
它们是不准确的。
-
对于具有大量特征的大数据集,它们可能会变得非常复杂。想象一下具有 1,000 个特征的数据库——该数据集的决策树将具有非常深的深度,其计算将非常资源密集。
为了减轻所有这些缺点,开发了随机森林算法,该算法建立在决策树之上。有了这些知识,让我们继续下一个概念:随机森林。
随机森林简介
随机森林,也称为随机决策森林,是一种机器学习方法,在学习过程中构建大量决策树,并将单个决策树的结果分组或集成,以进行预测。随机森林用于解决分类和回归问题。对于分类问题,预测值是多数决策树预测的类别值。对于回归问题,计算单个树的平均或预测值,并将其作为预测值返回。
随机森林算法在训练过程中遵循以下步骤进行学习:
-
从原始数据集中创建一个 bootstrap 数据集。
-
随机选择数据特征的一个子集。
-
使用所选特征子集开始创建决策树,其中将最佳分割数据的特征选为根节点。
-
选择其他剩余特征的一个随机子集以进一步分割决策树。
让我们通过创建一个来理解随机森林的概念。
我们将使用与我们在图 5.17中创建复杂决策树相同的同一个数据集。该数据集是我们创建决策树时使用的同一个数据集。要创建随机森林,我们需要创建数据集的 bootstrap 版本。
自助采样数据集是从原始数据集中随机选择行创建的数据集。自助采样数据集与原始数据集大小相同,也可以包含原始数据集中的重复行。有许多内置函数可以创建自助采样数据集,您可以使用其中的任何一个来创建一个。
考虑以下自助采样数据集:
图 5.21 – 自助采样数据集
下一步是从自助采样数据集中创建决策树,但在每个步骤中只使用特征列的子集。因此,选择所有要考虑的特征仅允许您使用良好的血液循环和阻塞动脉作为决策树的特性。
我们将遵循相同的纯度识别标准来确定节点的根。让我们假设在我们的实验中,良好的血液循环是最纯的。将其设置为根节点后,我们现在将考虑剩余的特征以填充决策节点的下一级。就像我们之前做的那样,我们将从剩余的特征中随机选择两个特征,并决定哪个特征应该适合下一个决策节点。我们将像往常一样构建树,同时考虑每个步骤中剩余变量的随机子集。
这里就是我们刚刚创建的树:
图 5.22 – 来自自助采样数据集的第一个决策树
现在,我们在创建多个决策树的同时,进行自助采样并从随机树中选择特征。一个理想的随机森林将创建数百个决策树,如下所示:
图 5.23 – 来自不同自助采样数据集的多个决策树
这种通过随机实现创建的决策树的大量多样性使得随机森林比单个决策树更有效。
现在我们已经创建了我们的随机森林,让我们看看我们如何使用它来进行预测。为了进行预测,您将有一行包含不同特征的数据值,并且您想要预测这个人是否有心脏病。
您将把这个数据传递给随机森林中的单个决策树:
图 5.24 – 随机森林中第一个决策树的预测
决策树将根据其结构预测结果。我们将跟踪此树所做的预测,并将数据继续传递给其他树,同时记录它们的预测:
图 5.25 – 随机森林中其他单个树所做的预测
一旦我们从所有单个树中得到预测,我们可以找出哪个值从所有决策树中获得最多的投票。获得最多投票的预测值即为随机森林的预测结果。
对数据集进行重采样并汇总所有决策树的预测值以做出决策的过程称为袋装法。
恭喜——你刚刚理解了随机森林的概念!尽管随机森林是一个非常优秀的 ML 算法,具有低偏差和方差,但它仍然面临着高计算需求的问题。因此,H2O AutoML 不是训练随机森林,而是训练随机森林的另一种版本,称为极度随机树(XRT)。
理解极度随机树
XRT算法,也称为ExtraTrees,与普通的随机森林算法类似。然而,随机森林和 XRT 之间有两个关键的区别,如下所示:
-
在随机森林中,我们使用重采样的数据集来训练单个决策树。在 XRT 中,我们使用整个数据集来训练单个决策树。
-
在随机森林中,决策节点是根据某些选择标准(如构建单个决策树时的不纯度指标或错误率)进行分裂的。在 XRT 中,这个过程是完全随机的,选择结果最好的进行选择。
让我们考虑之前用来理解随机森林的相同例子,以理解 XRT。我们有一个数据集,如图 5.17 所示。与图 5.20 中我们进行数据重采样不同,我们将直接使用原始数据集。
然后,我们开始通过随机选择特征子集来创建我们的决策树。在随机森林中,我们使用纯度标准来决定哪个特征应被设置为决策树的根节点。然而,对于 XRT,我们将随机设置决策树的根节点以及决策节点。同样,我们将创建具有所有特征随机选择的多个类似决策树。这种增加的随机性允许算法进一步减少模型的方差,但代价是略微增加偏差。
恭喜!我们刚刚研究了 XRT 算法如何使用极度随机的决策树来做出准确的回归和分类预测。现在,让我们了解 GBM 算法如何训练一个分类模型来对数据进行分类。
理解梯度提升机算法
梯度提升机(GBM)是一种前向学习集成 ML 算法,它适用于分类和回归。GBM 模型与 DRF 算法类似,是一个集成模型,因为 GBM 模型整体上是多个弱学习器模型的组合,其结果被汇总并作为 GBM 预测呈现。GBM 的工作方式与 DRF 类似,它由多个决策树组成,这些树按顺序构建,以逐步最小化误差。
GBM 可以用来预测连续数值,也可以用来分类数据。如果我们使用 GBM 来预测连续数值,我们说我们在使用 GBM 进行回归。如果我们使用 GBM 来分类数据,那么我们说我们在使用 GBM 进行分类。
GBM 算法与 DRF 一样,建立在决策树的基础上。然而,与 DRF 相比,决策树的构建方式不同。
让我们尝试理解 GBM 算法在回归中的工作原理。
构建梯度提升机
我们将使用以下样本数据集,并在概念上构建模型的同时理解 GBM 的工作原理。以下表格包含数据集的一个样本:
图 5.26 – GBM 的样本数据集
这是一个我们仅为了理解 GBM 如何构建其机器学习模型而使用的任意数据集。数据集的内容如下:
-
身高:这一列表示人的身高(厘米)。
-
性别:这一列表示人的性别。
-
年龄:这一列表示人的年龄。
-
权重:这一列表示人的权重。
与 DRF 不同,GBM 从叶节点而不是根节点开始创建其弱学习决策树。它将创建的第一个叶节点将是响应变量所有值的平均值。因此,相应地,GBM 算法将创建叶节点,如下面的图表所示:
图 5.27 – 使用列平均值计算叶节点
这个叶节点本身也可以被视为一个决策树。它像一个预测模型,只为任何类型的输入数据预测一个常数值。在这种情况下,它是我们从响应列得到的平均值。正如我们所预期的那样,这是一种错误的预测方式,但它只是 GBM 的第一步。
GBM 接下来要做的事情是创建另一个基于它在数据集上对初始叶节点预测观察到的错误的决策树。正如我们之前讨论的,错误不过是观察到的权重与预测的权重之间的差异,也称为残差。然而,这些残差与我们最终从完整的 GBM 模型中得到的实际残差不同。我们从 GBM 的弱学习决策树得到的残差称为伪残差,而 GBM 模型的残差是实际残差。
因此,正如之前提到的,GBM 算法将为数据集中的所有数据值计算第一个叶节点的伪残差,并创建一个特殊列来跟踪这些伪残差值。
参考以下图表以获得更好的理解:
图 5.28 – 带有伪残差的数据集
使用这些伪残差值,GBM 算法然后使用所有剩余的特征(即身高、最喜欢的颜色和性别)构建一个决策树。决策树将如下所示:
图 5.29 – 使用伪残差值的决策树
如您所见,这个决策树只有四个叶节点,而算法从第一个树生成的伪残差值远远超过四个。这是因为 GBM 算法限制了它所制作的决策树的大小。对于这种情况,我们只使用四个叶节点。数据科学家可以通过在配置 GBM 算法时传递正确的超参数来控制树的大小。理想情况下,对于大型数据集,您通常使用 8 到 32 个叶节点。
由于决策树中叶节点的限制,决策树最终在同一个叶节点中有多个伪残差值。因此,GBM 算法用它们的平均值替换它们,以得到一个单一叶节点的具体数字。相应地,在计算平均值后,我们将得到如下所示的决策树:
图 5.30 – 使用平均伪残差值的决策树
现在,算法将原始叶节点与这个新的决策树结合起来,对其做出预测。因此,现在,我们从初始叶节点预测中得到一个值为 71.2。然后,在将数据运行通过决策树后,我们得到 16.8。所以,预测的权重是这两个预测的总和,即 88。这也是观察到的权重。
这是不正确的,因为这是一个过拟合的例子。过拟合是一种建模错误,其中模型函数过于精细地调整,只能预测数据集中可用的数据值,而不能预测数据集外的任何其他值。结果,模型对于预测数据集外的任何值都变得无用。
因此,为了纠正这一点,GBM 算法为其训练的所有弱学习决策树分配一个学习率。学习率是一个超参数,它调整模型学习新信息(可以覆盖旧信息)的速度。学习率的值范围从 0 到 1。通过将这个学习率添加到决策树的预测中,算法控制决策树预测的影响,并逐步缓慢地朝着最小化误差的方向移动。在我们的例子中,假设学习率为 0.1。因此,相应地,预测的权重可以计算如下:
图 5.31 – 计算预测权重
因此,算法将为决策树做出的预测插入学习率,然后计算预测权重。现在,预测权重将是62.1 + (0.1 x -14.2) = 60.68。
60.68 不是一个很好的预测,但它仍然比初始叶节点预测的 62.68 要好。最小化误差的增量步骤是保持预测低方差的方法。正确的学习率平衡也同样重要,因为过高的学习率会导致校正方向相反,而过低的学习率会导致计算时间过长,因为算法将采取非常小的校正步骤以达到最小误差。
为了进一步校正预测值并最小化误差,GBM 算法将创建另一棵决策树。为此,它将从叶节点和第一棵决策树做出的预测中计算新的伪残差值,并使用这些值来构建第二棵决策树。
下图显示了如何计算新的伪残差值:
图 5.32 – 计算新的伪残差值
你会注意到,生成的新伪残差值与第一组伪残差值相比,更接近实际值。这表明 GBM 模型正在逐渐减少误差并提高其准确性。
继续使用第二棵决策树,算法使用新的伪残差值来创建第二棵决策树。一旦创建,它将树和学习率聚合到已经存在的叶节点和第一棵决策树中。
决策树每次 GBM 算法创建时可能都不同。然而,学习率对所有树都是通用的。因此,现在预测值将是三个组成部分的总和——初始叶节点预测值、第一棵决策树预测值的缩放值和第二棵决策树预测值的缩放值。因此,预测值如下所示:
图 5.33 – 带有第二棵提升决策树的 GBM 模型
GBM 算法将重复相同的过程,创建决策树,直到达到指定的树的数量或直到添加决策树不再提高预测为止。因此,GBM 模型最终将如下所示:
图 5.34 – 完整的 GBM 模型
恭喜!我们刚刚探讨了 GBM 算法如何使用一系列弱决策树学习器来做出准确的回归预测。
H2O AutoML 使用的另一种算法,它建立在 GBM 之上,是 XGBoost 算法。XGBoost 代表极端梯度提升(Extreme Gradient Boosting),实现了一种称为提升(boosting)的过程,有时有助于训练性能更好的模型。它是 Kaggle 竞赛中最广泛使用的机器学习算法之一,并且已被证明是一种出色的机器学习算法,可用于分类和回归。XGBoost 背后的数学对于不熟悉统计学的用户来说可能有些困难。然而,强烈建议您花时间学习更多关于这个算法的知识。您可以在docs.h2o.ai/h2o/latest-stable/h2o-docs/data-science/xgboost.xhtml
找到有关 H2O 如何执行 XGBoost 训练的更多信息。
小贴士
集成机器学习(Ensemble ML)是一种将多个机器学习模型组合起来以获得比单个模型性能更好的预测结果的方法——就像决策树组合成随机森林算法一样,使用袋装法,以及 GBM 算法使用弱学习者的组合来最小化错误。集成模型通过找到最佳的预测算法组合,并使用它们的组合性能来训练一个提供改进性能的元学习器,从而更进一步。这是通过称为堆叠的过程来完成的。您可以在docs.h2o.ai/h2o/latest-stable/h2o-docs/data-science/stacked-ensembles.xhtml#stacked-ensembles
找到有关 H2O 如何训练这些堆叠集成模型的更多信息。
现在,让我们学习深度学习的工作原理,并理解神经网络。
理解什么是深度学习
深度学习(DL)是机器学习的一个分支,它使用人工神经网络(ANNs)来开发预测模型。人工神经网络(ANNs),简称为神经网络(NNs),是基于人类大脑中神经元如何处理信息而松散构建的计算。人工神经网络由神经元组成,这些神经元是相互连接的其他神经元类型的节点。这些神经元在彼此之间传输信息;这些信息在神经网络中处理,最终得到一个结果。
深度学习(DL)是最强大的机器学习(ML)技术之一,用于训练高度可配置的模型,这些模型可以支持对大型和复杂数据集的预测。深度学习模型可以是监督的、半监督的或无监督的,这取决于它们的配置。
ANNs 有多种类型:
- 循环神经网络(RNN):RNN 是一种神经网络,其中神经网络中各个神经元之间的连接可以形成一个有向或无向图。这种类型的网络是循环的,因为网络的输出被送回到网络的起点,并有助于下一个预测周期的下一个循环。以下图显示了 RNN 的一个示例:
图 5.35 – RNN
如您所见,神经网络中最后节点的值被作为输入馈送到网络的起始节点。
- 前馈神经网络:前馈神经网络与 RNN 相似,唯一的区别是节点的网络不形成一个循环。以下图表显示了一个前馈神经网络的示例:
图 5.36 – 前馈神经网络
如您所见,这种类型的神经网络是单向的。这是最简单的 ANN 类型。前馈神经网络也称为深度神经网络(DNN)。
H2O 的深度学习(DL)基于多层前馈神经网络。它使用随机梯度下降和反向传播进行训练。H2O 可以训练多种不同类型的 DNN。具体如下:
-
多层感知器(MLP):这类 DNN 最适合表格数据。
-
卷积神经网络(CNN):这类 DNN 最适合图像数据。
-
循环神经网络(RNN):这类 DNN 最适合序列数据,如语音数据或时间序列数据。
建议使用 H2O 提供的默认 DNN,因为对于非专家来说,配置 DNN 可能非常困难。H2O 已经预先配置了其深度学习实现,以使用针对给定情况的最佳类型的 DNN。
在了解这些基础知识后,让我们更深入地了解深度学习是如何工作的。
理解神经网络
NN是深度学习的基础。神经网络的工作原理易于理解:
-
您将数据输入到神经网络的输入层。
-
神经网络中的节点通过自身训练来识别输入数据中的模式和行。
-
神经网络根据在训练期间学习的模式和行进行预测。
神经网络的架构如下:
图 5.37 – 神经网络的架构
神经网络(NN)有三个基本组成部分:
-
输入层:输入层由多个神经元集组成。这些神经元连接到下一层的神经元,这些神经元位于隐藏层。
-
隐藏层:在隐藏层中,可以有多个神经元层,这些神经元层逐层相互连接。
-
输出层:输出层是神经网络中的最后一层,它进行最终计算以计算最终预测值(以概率形式)。
神经网络的学习过程可以分为两个部分:
- 前向传播:正如其名所示,前向传播是信息从输入层通过中间层流向输出层的过程。以下图表显示了前向传播的实际操作:
图 5.38 – 神经网络中的前向传播
中间层中的神经元通过通道连接。这些通道被分配了称为权重的数值。权重决定了神经元在贡献整体预测中的重要性。权重值越高,该节点在预测时的重要性就越大。
输入层的输入值在通过通道时乘以这些权重,它们的总和作为输入发送到隐藏层中的神经元。隐藏层中的每个神经元都与一个称为偏置的数值相关联,该数值被添加到输入总和。
这个加权值随后传递到一个称为激活函数的非线性函数。激活函数是一个函数,它根据非线性函数的方程决定特定的神经元是否可以将计算出的权重值传递到下一层的神经元。偏置是一个标量值,它将激活函数向左或向右移动以进行校正。
这种信息流继续传递到隐藏层的下一层神经元,遵循相同的乘以通道权重并将输入传递到节点的下一个激活函数的过程。
最后,在输出层,具有最高值的神经元决定了预测值,这是一种概率的形式。
- 反向传播:反向传播的工作方式与正向传播相同,只是它的工作方向相反。信息以相反的方式从输出层通过隐藏层传递到输入层。以下图表将更好地帮助您理解这一点:
图 5.39 – 神经网络中的反向传播
由于反向传播从输出到输入以相反的方式工作,理解其工作原理可能有些反直觉,但这是一个使深度学习对机器学习如此强大的概念。正是通过反向传播,神经网络能够自主学习。
它这样做的方式相当简单。在反向传播学习中,神经网络将计算预期值和预测值之间的误差幅度,并通过将其映射到一个损失函数来评估其性能。损失函数是一个计算预测值和预期值之间偏差的函数。这个偏差值是帮助神经网络调整其隐藏层中的偏置和权重以改进性能和做出更好预测的信息。
恭喜您 – 我们刚刚对深度学习如何训练机器学习模型有了基本的了解!
小贴士
深度学习(DL)是机器学习中最复杂的领域之一,也是人工智能作为一个整体。这是一个庞大的机器学习专业化领域,数据科学家在这里花费大量时间研究并理解他们正在处理的问题陈述和数据,以便他们可以正确调整他们的深度学习神经网络(NN)。其背后的数学也非常复杂,因此值得有一本专门的书籍。所以,如果你对数学感兴趣并想在深度学习艺术上脱颖而出,请自由地深入研究机器学习算法,因为理解它的每一步都会使你成为一个更加专业的机器学习工程师。你可以在docs.h2o.ai/h2o/latest-stable/h2o-docs/data-science/deep-learning.xhtml
找到更多关于 H2O 如何执行深度学习训练的信息。
摘要
在这一章中,我们了解了不同类型的预测问题以及各种算法如何试图解决这些问题。然后,我们了解了不同的机器学习算法是如何根据它们从数据中学习的方法被分类为监督学习、无监督学习、半监督学习和基于强化学习的。一旦我们对机器学习的整体问题领域有了理解,我们就明白 H2O AutoML 只训练监督学习的机器学习算法,并且可以专门解决这个领域的预测问题。
然后,我们了解了 H2O AutoML 从 GLM 开始训练的算法。为了理解 GLM,我们了解了线性回归是什么以及它是如何工作的,以及它必须对数据的正态分布做出哪些假设才能有效。带着这些基础知识,我们理解了 GLM 是如何被推广以有效性的,即使这些线性回归的假设得到满足,这在现实生活中是一个常见的情况。
然后,我们学习了随机森林(DRF)。为了理解 DRF,我们了解了决策树是什么——即 DRF 的基本构建块。然后,我们了解到,具有集成学习的多个决策树比普通的决策树是更好的机器学习模型——这就是随机森林的工作原理。在此基础上,我们学习了 DRF 如何通过 XRT 的形式增加更多的随机化,使算法在低方差和偏差的情况下更加有效。
之后,我们学习了梯度提升机(GBM)。我们了解到 GBM 与 DRF 相似,但它有稍微不同的学习方法。我们理解了 GBM 是如何顺序地构建决策树,并通过从先前决策树预测的残差中学习来逐渐最小化错误的。
最后,我们学习了什么是深度学习。我们理解了神经网络是深度学习的基础构建块以及它们的类型。我们还理解了神经网络如何通过其结果进行反向传播学习,并通过调整中间层神经元的权重和偏差来自我学习和改进模型。
本章为您提供了对 H2O AutoML 如何训练各种机器学习算法的简要概念性理解,而没有深入到数学层面。然而,对于那些想要成为机器学习领域专家并希望解决复杂机器学习问题的机器学习爱好者来说,强烈建议您理解机器学习算法奇妙世界背后的数学原理。正是由于科学家和像您这样的爱好者多年的研究和努力,我们今天才有可能在机器的帮助下预测未来。
在下一章中,我们将深入探讨如何使用不同的统计测量和其他指标来理解机器学习模型是否表现最优。这些指标能更详细地解释机器学习模型的表现。
第六章:理解 H2O AutoML 排行榜及其他性能指标
当我们训练机器学习模型时,不同算法的统计细微差别往往使得比较使用不同算法训练的模型变得困难。从专业角度来看,你最终需要选择合适的模型来解决你的机器学习问题。因此,问题随之而来:你如何比较解决相同机器学习问题的两个不同模型,并决定哪个更好?
这就是模型性能指标发挥作用的地方。模型性能指标是一系列数值指标,可以准确衡量模型的表现。模型的表现可以意味着许多不同的事情,也可以用多种方式来衡量。我们评估模型的方式,无论是分类模型还是回归模型,只取决于我们用于评估的指标。你可以通过测量正确和错误预测的数量来衡量模型分类对象的准确性。你可以通过测量模型预测股票价格的准确性,并注意预测值与实际值之间的误差幅度。你也可以比较模型在数据异常值上的表现。
H2O 提供了大量的模型性能测量技术。其中大多数都是在模型训练时自动计算并存储为模型元数据的。H2O AutoML 还进一步自动化了模型的选择。它通过向你展示一个比较训练模型不同性能指标的排行榜来实现这一点。在本章中,我们将探讨 AutoML 排行榜中使用的不同性能指标,以及一些对用户来说很重要的附加指标。
我们将根据以下章节来探讨这些性能指标:
-
探索 H2O AutoML 排行榜性能指标
-
探索其他重要的性能指标
到本章结束时,你应该了解如何衡量模型的表现,以及我们如何使用这些指标来了解其预测行为。
因此,让我们从探索和理解 H2O AutoML 排行榜性能指标开始。
探索 H2O AutoML 排行榜性能指标
在第二章 使用 H2O Flow (H2O 的 Web UI) 中,一旦我们使用 H2O AutoML 在数据集上训练了模型,模型的成果就会存储在排行榜中。排行榜是一个包含模型 ID 和相应模型某些指标值的表格(见图 2.33)。
排行榜根据默认指标对模型进行排名,理想情况下是表格的第二列。排名指标取决于模型训练的预测问题类型。以下列表表示用于相应机器学习问题的排名指标:
-
对于二分类问题,排名指标是AUC。
-
对于多分类问题,排名指标是每类平均误差。
-
对于回归问题,排名指标是偏差。
除了排名指标外,排行榜还提供了一些额外的性能指标,以更好地理解模型质量。
让我们尝试理解这些性能指标,从均方误差开始。
理解均方误差和均方根误差
均方误差(MSE),也称为均方偏差(MSD),正如其名所示,是一个指标,它衡量预测值与实际值误差的平方的平均值。
考虑以下回归场景:
图 6.1 - 回归场景中的 MSE
这是一个通用的回归场景,其中回归线穿过图表上绘制的数据点。训练好的模型根据这条回归线进行预测。误差值显示了实际值与预测值之间的差异,这些差异位于回归线上,如红色线条所示。这些误差也称为残差。在计算 MSE 时,我们平方这些误差以消除任何负号,因为我们只关心误差的大小,而不是其方向。平方也赋予了较大的误差值更多的权重。一旦计算了所有数据点的平方误差,我们就计算平均值,这给出了最终的 MSE 值。
MSE 是一个指标,它告诉你回归线有多接近数据点。相应地,回归线与数据点之间的误差值越少,你的 MSE 值就越低。因此,在比较不同模型的 MSE 时,具有较低 MSE 的模型理想上是更准确的模型。
MSE 的数学公式如下:
在这里,n将是数据集中的数据点数量。
均方根误差(RMSE),正如其名所示,是均方误差的平方根。因此,其数学公式如下:
MSE 和 RMSE 之间的区别是直接的。虽然 MSE 是在响应列的平方单位中测量的,但 RMSE 是在与响应列相同的单位中测量的。
例如,如果你有一个线性回归问题,它以美元为单位预测其股票的价格,MSE 以平方美元为单位衡量误差,而 RMSE 将误差值仅以美元为单位衡量。因此,RMSE 通常比 MSE 更容易解释模型质量。
恭喜——你现在已经了解了 MSE 和 RMSE 指标是什么以及它们如何用于衡量回归模型的性能。
让我们继续到下一个重要的性能指标,即混淆矩阵。
与混淆矩阵一起工作
分类问题是一个机器学习问题,其中机器学习模型试图将数据输入分类到预指定的类别中。与回归模型相比,分类模型性能测量的不同之处在于,在分类问题中,预测值与实际值之间没有数值误差。预测值要么被正确分类到正确的类别,要么被错误分类。为了衡量分类问题的模型性能,数据科学家依赖于从称为混淆矩阵的特殊类型矩阵中派生出的某些性能指标。
混淆矩阵是一个表格矩阵,总结了分类问题的预测结果正确性。该矩阵并列展示了正确和错误的预测值,并按每个类别进行细分。这个矩阵被称为混淆矩阵,因为它显示了模型在分类值时的困惑程度。
以我们使用的冠心病预测数据集为例。这是一个二元分类问题,我们想要预测具有某些健康条件的人是否可能患有冠心病。在这种情况下,预测结果是是,也称为正分类,意味着该人可能患有冠心病,或者否,也称为负分类,意味着该人不太可能患有冠心病。
该场景的混淆矩阵如下所示:
图 6.2 – 二项式混淆矩阵
混淆矩阵的行对应于模型预测的分类。混淆矩阵的列对应于模型的实际类值。
在矩阵的左上角,我们有真正例 – 这些是正确预测为“是”的实际“是”的数量。在右上角,我们有假正例 – 这些是错误预测为“否”的实际“是”的数量。在左下角,我们有假负例 – 这些是错误预测为“是”的实际“否”的数量。最后,我们还有真负例 – 这些是正确预测为“否”的实际“否”的数量。
对于具有六个可能类别的多项式分类,混淆矩阵将如下所示:
图 6.3 – 多项式混淆矩阵
使用两个分类模型的混淆矩阵,您可以比较个别算法预测的真正例和真负例的数量,并选择正确预测数量更多的模型作为更好的模型。
尽管使用混淆矩阵很容易解释模型的预测质量,但仅基于真正阳性和真正阴性的数量比较两个或多个模型仍然很困难。
考虑一个场景,你想要对一些医疗记录进行分类,以确定患者是否有脑瘤。假设一个特定模型的混淆矩阵相对于其他模型具有高数量的真正阳性和真正阴性,同时也有高数量的假阳性。在这种情况下,该模型将错误地将许多正常医疗记录标记为潜在脑瘤的迹象。这可能导致医院做出错误的决定,进行不必要的风险手术。在这种情况下,具有较低准确率但假阳性数量最少的模型更可取。
因此,在混淆矩阵的基础上开发了更复杂的指标。它们如下:
- 准确度:准确度是一个衡量与总预测数相比正确预测的阳性和阴性预测数的指标。计算方法如下:
在这里,缩写代表以下内容:
-
TP 代表真正阳性。
-
TN 代表真正阴性。
-
FP 代表假阳性。
-
FN 代表假阴性。
当你想比较分类模型正确预测的能力,无论预测值是阳性还是阴性时,这个指标很有用。
- 精确度:精确度是一个衡量与总预测数相比正确阳性预测数的指标。计算方法如下:
当测量在具有大量阴性结果和少量阳性结果的训练数据上训练的分类模型的性能时,这个指标特别有用。精确度不受正负分类值不平衡的影响,因为它只考虑阳性值。
- 敏感性或召回率:敏感性,也称为召回率,是衡量模型预测真正阳性的概率测量值。敏感性是通过识别在二项式分类中预测中被正确识别为阳性的预测百分比来衡量的。计算方法如下:
如果你的分类机器学习问题旨在准确识别所有正预测,那么模型的敏感性应该很高。
- 特异性:虽然敏感性是衡量模型预测真正阳性的概率测量值,但特异性是通过识别在二项式分类中被正确识别为阴性的预测百分比来衡量的。计算方法如下:
如果你的分类机器学习问题旨在准确识别所有负预测,那么模型的特异性应该很高。
敏感度和特异性之间始终存在权衡。一个具有高敏感度的模型通常具有非常低的特异性,反之亦然。因此,机器学习问题的上下文在决定你是否想要一个具有高敏感度或高特异性的模型来解决问题中起着非常重要的作用。
对于多项式分类,你需要为每个类别类型计算敏感度和特异性。对于敏感度,你的真正例将保持不变,但假阴性将根据对该类别的错误预测数量而变化。同样,对于特异性,真正例将保持不变——然而,假阳性将根据对该类别的错误预测数量而变化。
现在你已经了解了如何使用混淆矩阵来衡量分类模型,以及敏感度和特异性是如何建立在它之上的,那么我们现在继续到下一个指标,即受试者工作特征曲线及其曲线下面积。
计算受试者工作特征及其曲线下面积(ROC-AUC)
比较分类模型的另一种好方法是通过对它们性能的视觉表示。最广泛使用的视觉评估指标之一是受试者工作特征及其曲线下面积(ROC-AUC)。
ROC-AUC 指标分为两个概念:
-
ROC 曲线:这是在图表上绘制的图形曲线,总结了模型在各个阈值下的分类能力。阈值是一个分类值,用于将数据点分为不同的类别。
-
AUC:这是 ROC 曲线下的面积,帮助我们比较哪个分类算法表现更好,取决于哪个 ROC 曲线覆盖的面积最大。
让我们通过一个例子来更好地理解 ROC-AUC 如何帮助我们比较分类模型。参考以下样本数据集:
图 6.4 – 肥胖数据集
该数据集有两个列:
-
体重(千克):这是一个数值列,包含一个人的体重(千克)
-
肥胖:这是一个分类列,包含1或0,其中1表示该人肥胖,0表示该人非肥胖
让我们将这个数据集绘制到图表上,其中体重作为自变量位于x轴上,肥胖作为因变量位于y轴上。这个简单的数据集在图表上看起来如下:
图 6.5 – 绘制的肥胖数据集
让我们使用一种称为逻辑回归的简单分类算法之一,通过这些数据拟合一个分类线。逻辑回归是一种预测给定数据样本属于某个特定类的概率的算法。在我们的例子中,该算法将根据体重预测一个人是否肥胖的概率。
逻辑回归线将如下所示:
图 6.6 – 使用分类线绘制的肥胖数据集
注意,由于逻辑回归预测数据可能属于某个特定类的概率,我们已经将y轴转换为一个人肥胖的概率。
在预测期间,我们首先将人的样本体重数据绘制在x轴上。然后,我们将在分类线上找到其相应的y值。这个值是相应的人肥胖的概率。
现在,为了判断一个人是否肥胖,我们需要决定将肥胖和非肥胖区分开来的概率截止线是什么。这条截止线被称为阈值。任何高于阈值的概率值都可以被归类为肥胖,而任何低于阈值的值都可以被归类为非肥胖。阈值可以是 0 到 1 之间的任何值:
图 6.7 – 使用阈值线对肥胖数据集进行分类
如您从图中可以看出,多个值被错误地分类。这在任何分类问题中都是不可避免的。因此,为了跟踪正确和错误的分类,我们将创建一个混淆矩阵,并计算灵敏度和特异性来评估模型在所选阈值下的表现。
但如前所述,分类可以有多个阈值。具有高值的阈值将最小化假阳性的数量,但代价是分类将变得更加严格,导致更多的假阴性。同样,如果阈值值太低,那么我们最终会得到更多的假阳性。
哪个阈值表现最好取决于你的机器学习问题。然而,需要比较不同阈值的研究来找到一个合适的值。由于你可以创建任意数量的阈值,你最终会创建大量的混淆矩阵。这就是 ROC-AUC 指标发挥作用的地方。
ROC-AUC 指标总结了模型在不同阈值下的性能,并在图上绘制它们。在这个图中,x轴是假阳性率,即1 - 特异性,而y轴是真阳性率,也就是灵敏度。
让我们绘制我们的样本数据集的 ROC 图。我们将从使用一个将所有样本归类为肥胖的阈值开始。图上的阈值将如下所示:
图 6.8 – 使用非常低的阈值绘制的肥胖分类
现在,我们需要计算绘制 ROC 曲线所需的敏感性(和 1 - 特异性)值,因此相应地,我们首先需要创建一个混淆矩阵。这个阈值的混淆矩阵看起来如下:
图 6.9 – 包含敏感性和 1 - 特异性的混淆矩阵
使用之前提到的公式计算敏感性和 1 - 特异性值,我们得到一个等于1的敏感性和一个等于0.5的 1 - 特异性。让我们在 ROC 图上绘制这个值。ROC 图将看起来如下:
图 6.10 – ROC 图
图表中的蓝色线表示敏感性等于 1 - 特异性——换句话说,真正阳性率等于假阳性率。任何位于这条线上的 ROC 点都表明,使用此阈值训练的模型预测正确阳性的可能性与预测错误阳性的可能性相同。因此,为了找到最佳阈值,我们旨在找到一个具有尽可能高的敏感性和尽可能低的 1 - 特异性的 ROC 点。这将表明模型有很高的可能性预测正确的阳性预测,并且预测错误阳性的可能性要小得多。
现在,让我们提高阈值并重复相同的过程来计算这个新阈值的 ROC 值。让我们假设这个新阈值的敏感性为 1,1 - 特异性为 0.25。在 ROC 图上绘制这个值,我们得到以下结果:
图 6.11 – 使用新阈值的 ROC 图
新阈值的 ROC 值位于蓝色线的左侧,也位于之前的 ROC 点。这表明它比之前的阈值具有更低的假阳性率。因此,新的阈值比之前的阈值更好。
将阈值值调得过高会导致模型预测所有值都不是肥胖的。基本上,它将错误地将所有值预测为假,增加了假阴性的数量。根据敏感性方程,假阴性的数量越多,敏感性越低。因此,这最终会降低您的敏感性,减少模型预测真正阳性的能力。
我们会为不同的阈值值重复进行相同的过程,并在 ROC 图上绘制它们的 ROC 值。如果我们连接所有这些点,我们得到 ROC 曲线:
图 6.12 – 包含 ROC 曲线的 ROC 图
只需通过观察 ROC 图,就可以确定哪些阈值值比其他阈值值更好,并且根据你的机器学习问题可以容忍多少假阳性预测,你可以选择具有正确假阳性率的 ROC 点作为你的最终阈值值参考。这解释了 ROC 曲线的作用。
现在,假设你有一个使用不同阈值训练的另一个算法,你将它的 ROC 点绘制到这个相同的图上。假设绘制结果如下:
图 6.13 – 带有多个 ROC 曲线的 ROC 图
你会如何比较哪个算法表现更好?哪个阈值是该算法模型的最佳选择?
这就是 AUC 帮助我们的地方。AUC 不过是 ROC 曲线下的面积。整个 ROC 图将有一个总面积为1。红色线将面积分成两半,因此理想情况下,所有潜在的好算法都应该有大于 0.5 的 AUC。AUC 值越大,算法越好:
图 6.14 – ROC 曲线的 AUC
只需通过可视化,你就可以看到哪个算法的 AUC 值更高。同样,AUC 值帮助工程师和科学家确定选择哪个算法以及使用哪个阈值作为最佳机器学习模型进行分类。
恭喜你,你现在已经理解了 ROC-AUC 指标的工作原理以及它是如何帮助你比较模型性能的。现在,让我们继续介绍另一个类似性能指标,称为精确率-召回率曲线(PR 曲线)。
计算精确率-召回率曲线及其曲线下面积(AUC-PR)
使用 ROC-AUC,尽管这是一个非常好的比较模型的指标,但完全依赖它也存在一些小缺点。在一个非常不平衡的数据集中,其中存在大量真实负值,ROC 图的x轴将会非常小,因为特异性以真实负值为分母。这迫使 ROC 曲线向图的左侧移动,使得 ROC-AUC 值接近 1,这在技术上是不正确的。
这就是 PR 曲线发挥作用的地方。PR 曲线与 ROC 曲线类似,唯一的区别是 PR 曲线是一个函数,它在y轴上使用精确率,在x轴上使用召回率。精确率和召回率的计算都不使用真实负值。因此,当数据集的类别不平衡影响预测中的真实负值,或者当你的机器学习问题根本不关心真实负值时,PR 曲线及其 AUC 指标是合适的。
让我们通过一个例子进一步了解 PR 曲线。我们将使用与理解 ROC-AUC 曲线相同的样本肥胖数据集。将数据集的记录绘制到图上并创建其混淆矩阵的过程与 ROC-AUC 曲线相同。
现在,我们不再从混淆矩阵中计算敏感度和 1 – 特异性,而是这次我们将计算精确率和召回率值:
图 6.15 – 计算精确率和召回率值
如前图所示,我们得到了精确率为0.625和召回率为1。让我们将这些值绘制到下面的 PR 图中,如图所示:
图 6.16 – PR 图
同样,通过移动阈值线并创建新的混淆矩阵,精确度和召回率值将根据混淆矩阵中预测的分布而变化。我们重复这个过程,为不同的阈值值计算精确度和召回率值,然后将它们绘制到 PR 图上:
图 6.17 – PR 图及其 PR 曲线
连接所有点的蓝色线是 PR 曲线。代表阈值值最接近黑色点的点,即最接近具有 1 的精确度和 1 的召回率的理想分类器。
当比较不同的算法模型时,你将在 PR 图中看到多个 PR 曲线:
图 6.18 – 包含多个 PR 曲线的 PR 图
上述图表显示了可以在同一图表上绘制的多个 PR 曲线,以提供不同算法性能的更好比较视图。只需一眼,你就可以看到代表蓝色线的算法的阈值值最接近黑色点,理想情况下应该是性能最好的模型。
就像 ROC-AUC 一样,你也可以使用 AUC-PR 来计算 PR 曲线下的面积,以更好地理解不同算法的性能。基于此,你知道代表红色 PR 曲线的算法比代表黄色曲线的算法好,代表蓝色 PR 曲线的算法比红色和黄色曲线的算法都要好。
恭喜!你现在已经理解了 H2O AutoML 排行榜中的 AUC-PR 指标,以及它如何成为另一个良好的模型性能指标,在比较由 H2O AutoML 训练的模型时可以参考。
现在我们继续讨论下一个性能指标,它被称为对数损失。
对数损失的工作原理
对数损失是分类模型的重要模型性能指标之一。它主要用于衡量二元分类模型的性能。
对数损失是衡量分类模型性能的一种方式,该模型以概率值的形式输出分类结果。概率值可以从0开始,表示数据属于某个特定正类的概率为零,到1结束,表示数据属于某个特定正类的概率为 100%。对数损失值可以从 0 延伸到无穷大,所有机器学习模型的目的是尽可能最小化对数损失。任何对数损失值尽可能接近 0 的模型都被认为是性能更好的模型。
对数损失的计算完全是统计性的。然而,理解数学背后的直觉对于更好地理解其在比较模型性能时的应用非常重要。
对数损失是一个衡量预测概率与实际值之间差异的指标。因此,如果预测概率与实际值差异很小,那么你的对数损失值将会很宽容;然而,如果差异更大,对数损失值将会更加惩罚性。
让我们先了解预测概率是什么。我们将使用与 ROC-AUC 曲线相同的肥胖数据集。假设我们运行了一个分类算法,计算了预测该人肥胖的概率,并将这些值添加到数据集的列中,如下截图所示:
图 6.19 – 添加了预测概率的肥胖数据集
我们将有一个特定的阈值值,用于决定预测概率值必须是多少,我们才能将数据分类为肥胖或非肥胖。让我们假设阈值为 0.5 - 在这种情况下,预测概率值高于 0.5 被分类为肥胖,任何低于它的都被分类为非肥胖。
我们现在计算每个数据点的对数损失值。计算每个记录对数损失的公式如下:
这里,方程可以分解如下:
-
y 是实际分类值,即 0 或 1。
-
p 是预测概率。
-
log 是数字的自然对数。
在我们的例子中,因为我们使用肥胖类别作为参考,所以我们将 y 设置为 1。使用这个公式,我们计算单个数据值的对数损失值如下:
图 6.20 – 每条记录的对数损失值的肥胖数据集
现在,让我们将这些值绘制到对数损失图中,我们将对数损失值放在 y 轴上,预测概率放在 x 轴上:
图 6.21 – 对数损失图,其中 y = 1
你会注意到,随着预测概率偏离实际值,对数损失值呈指数增长。差异越小,对数损失的增幅就越小。这就是为什么对数损失是一个好的比较指标,因为它不仅比较哪个模型是好是坏,还比较它有多好或多坏。
同样,如果你想使用非肥胖类别作为对数损失的参考,那么你需要反转预测概率,计算对数损失值,并绘制图表,或者你也可以将 y 设置为 0 并使用计算出的对数损失值绘制对数损失图。这个图将是之前图的镜像(见图 6.21):
图 6.22 – 对数损失图,其中 y = 0
模型的 log 损失值,也称为模型的 技能,是数据集中所有记录的 log 损失值的平均值。因此,模型 log 损失的方程如下:
在这里,方程可以分解如下:
-
n 是数据集中的总记录数。
-
y 是实际的分类值,即 0 或 1。
-
p 是预测概率。
-
log 是数字的自然对数。
在一个理想的世界里,具有完美评分能力和技能的模型被认为具有等于 0 的 log 损失。为了正确应用 log 损失来比较模型,两个模型都必须使用相同的训练数据集进行训练。
恭喜!我们刚刚介绍了如何从统计角度计算 log 损失。在下一节中,我们将探讨一些其他重要的指标,这些指标虽然不是 H2O AutoML 排行榜的一部分,但在理解模型性能方面仍然很重要。
探索其他模型性能指标
H2O AutoML 排行榜基于某些常用的重要指标总结了模型性能。然而,在机器学习领域,仍然有许多性能指标描述了机器学习模型的不同技能。这些技能往往是你给定机器学习问题中什么工作得最好的决定因素,因此,了解我们如何使用这些不同的指标是很重要的。H2O 还通过在训练完成后计算这些指标并将它们存储为模型的元数据来为我们提供这些指标值。你可以通过使用内置函数轻松访问它们。
在接下来的小节中,我们将探讨一些其他重要的模型性能指标,从 F1 开始。
理解 F1 分数性能指标
精确率和召回率,尽管是衡量分类模型性能的非常好的指标,但存在权衡。精确率和召回率不能同时具有高值。如果你通过调整分类阈值来提高精确率,那么它会影响你的召回率,因为假阴性的数量可能会增加,从而降低你的召回率值,反之亦然。
精确度指标旨在最小化错误预测,而召回率指标旨在找到最多的积极预测。因此,技术上,我们需要在这两个指标之间找到正确的平衡。
这就是 F1 分数 性能指标出现的地方。F1 分数是一个试图同时最大化精确率和召回率的指标,并为模型性能给出一个总体分数。
F1 分数是精确度和召回率的调和平均值。调和平均值是计算值平均值的多种变体之一。使用调和平均值,我们计算所有观察值的倒数算术平均数的倒数。我们使用调和平均值来计算 F1 分数的原因是,使用一般的算术平均值会导致方程对所有程度的错误给予同等的重要性。另一方面,调和平均值通过相应地降低 F1 分数来惩罚高误差值。这就是为什么使用调和平均值生成 F1 分数的原因,因为计算出的分数值能更好地表示模型的性能。
F1 分数的范围是 0 到 1,其中 1 表示模型具有完美的精确度和召回率值,而 0 表示精确度或召回率值之一为 0。
计算 F1 分数的公式如下:
让我们以一个混淆矩阵为例:
图 6.23 – 带有精确度和召回率的示例混淆矩阵
让我们计算矩阵的精确度值:
同样,现在让我们计算矩阵的召回率值:
现在,将精确度和召回率的值代入 F1 分数公式中,我们得到以下结果:
我们得到了一个 F1 分数为0.15。你现在可以通过类似地计算另一个模型的 F1 分数并将其与这个分数进行比较来比较另一个模型的性能。如果新模型的 F1 分数大于0.15,那么该模型比这个模型表现更好。
F1 分数的好处是,在比较分类模型时,你不需要平衡多个模型的精确度和召回率值,并基于两个对比指标的比较做出决定。F1 分数总结了精确度和召回率的最佳值,这使得更容易确定哪个模型更好。
尽管是一个好的指标,但 F1 分数仍然存在某些缺点。首先,F1 分数在计算分数时没有考虑真正的负例。其次,F1 分数不足以捕捉多类分类问题的性能。技术上,你可以使用宏平均来计算多类分类问题的 F1 分数——然而,有更好的指标可以使用。
让我们看看一种克服 F1 分数缺点的指标,即绝对马修斯相关系数。
计算绝对马修斯相关系数
考虑一个例子,我们试图根据给定水果的大小预测它是否是葡萄还是西瓜。我们有 200 个样本,其中 180 个是葡萄,20 个是西瓜。很简单,是的——越大,越可能是西瓜,而较小的尺寸则表明它是葡萄。假设我们训练了一个以葡萄为正类的分类器。这个分类器能够如下分类水果:
图 6.24 – 以葡萄为正类的果实分类混淆矩阵
让我们快速计算之前提到的标量分类度量。
分类器的准确度如下:
分类器的精确度如下:
分类器的召回率如下:
分类器的 F1 分数如下:
根据这些度量值,我们的分类器在预测葡萄时似乎表现非常好。那么,如果我们想预测西瓜呢?让我们将正类从葡萄改为西瓜。这种情况下的混淆矩阵如下:
图 6.25 – 以西瓜为正类的果实分类混淆矩阵
我们将快速计算之前提到的标量分类度量。
分类器的准确度如下:
分类器的精确度如下:
分类器的召回率如下:
分类器的 F1 分数如下:
如我们从度量值中看到的那样,准确度保持不变,但精确度、召回率和 F1 分数急剧下降。尽管准确度、精确度、召回率和 F1 分数是衡量分类性能非常好的指标,但在数据集中存在类别不平衡时,它们也有一些缺点。在我们的葡萄和西瓜数据集中,我们只有 20 个西瓜样本,但葡萄有 180 个样本。这种数据不平衡会导致度量计算中的不对称,这可能具有误导性。
理想情况下,作为数据科学家和工程师,我们通常建议尽可能保持数据对称,以使这些指标的测量尽可能相关。然而,在包含数百万条记录的现实世界数据集中,保持这种对称性将非常困难。因此,拥有某种将正负类别视为相等并给出分类模型整体性能总体图的指标将是有益的。
这就是绝对 Matthews 相关系数(MCC),也称为phi 系数,发挥作用的地方。MCC 的方程如下:
在计算过程中,它将实际类别和预测类别视为两个不同的变量,并确定它们之间的相关系数。相关系数不过是一个数值,它代表了变量之间的某种统计关系。这个相关系数值越高,你的分类模型就越好。
MCC 值范围从-1 到 1。1 表示分类器是完美的,并且总是正确分类记录。MCC 为 0 表示类别与模型预测之间没有相关性,模型预测完全随机。-1 表示分类器总是错误地分类记录。
MCC 值为-1 并不意味着模型在任何一个方面都是不好的。它仅表示预测类别和实际类别之间的相关系数是负的。因此,如果你只是反转分类器的预测,你将总是得到正确的分类预测。此外,MCC 是完全对称的——因此,它平等地对待所有类别,以提供一个考虑模型整体性能的指标。切换正负类别不会影响 MCC 值。因此,如果你只是取 MCC 的绝对值,它仍然不会失去其相关性的价值。H2O 通常使用 MCC 的绝对值来更容易地理解模型的表现。
让我们计算以葡萄为正类的水果分类混淆矩阵的 MCC 值:
同样,让我们计算以西瓜为正类的水果分类混淆矩阵的 MCC 值:
如您所见,即使我们切换正负类别,MCC 值仍然保持不变,为0.277。一个 MCC 为0.277的值表明预测类别和实际类别之间相关性较弱,考虑到分类器在分类西瓜方面表现不佳,这是正确的。
恭喜你,你现在理解了另一个重要的指标,称为绝对 MCC(Matthews Correlation Coefficient)。
现在让我们转向下一个性能指标,即 R2。
测量 R2 性能指标
R2,也称为确定系数,是一个回归模型性能指标,旨在通过独立变量变化对因变量影响的大小来解释自变量和因变量之间的关系。
R2 的值介于 0 到 1 之间,其中 0 表示回归线没有正确捕捉到数据中的趋势,而 1 表示回归线完美地捕捉到了数据中的趋势。
让我们通过一个数据集的图形示例更好地理解这个指标。请参考下面的图像,以了解身高与体重回归图:
图 6.26 – 身高与体重回归图
数据集有两列:
-
身高:这是一个数值列,包含一个人的身高(厘米)。
-
体重:这是一个数值列,包含一个人的体重(千克)。
使用这个数据集,我们试图根据一个人的身高来预测他的体重。
因此,首先,让我们使用所有体重的平均值作为一般的回归线来预测体重。从技术上讲,这确实是有意义的,因为大多数成年人都会有平均范围的体重——尽管可能会有一些误差,但这仍然是一种合理的预测一个人体重的办法。
如果我们将这个数据集绘制在图上,用于预测的平均值将看起来如下:
图 6.27 – 带有平均线的身高与体重回归图
如您所见,预测的体重值(即平均值)与实际值之间肯定存在一些误差。如前所述,这种误差称为残差。计算残差的平方给我们平方误差。所有记录的这些平方误差之和给我们提供了围绕平均线的变异。
现在我们来进行线性回归,并拟合一条通过数据的线,以便我们得到另一条回归线。这条回归线理想上应该比仅使用平均值作为预测指标有更好的预测能力。图上的回归线应该看起来如下:
图 6.28 – 带有回归线的身高与体重回归数据集
让我们计算这条线的残差平方误差——这给我们提供了围绕回归线的变异。
现在,我们需要找出一种方法来识别哪条线更好,是回归线还是平均线,以及好多少。这正是 R2 可以用来比较两条回归线的地方。计算 R2 的公式如下:
假设回归线周围的残差平方和为 7,平均线周围的残差平方和为 56。将这些值代入 R2 公式,我们得到以下值:
值 0.875 是一个百分比。这个值解释了 87.5% 的 y 值的总变化是由 x 值的变化所描述的。剩余的 12.5% 可能是由于数据集中的一些其他因素,如肌肉量、脂肪含量或其他任何因素。
从机器学习(ML)的角度来看,R2 值越高,表示两个变量之间的关系解释了数据中的变化,因此线性模型已经准确地捕捉了数据集的模式。R2 值越低,表示线性模型并没有完全捕捉到数据集的模式,并且一定存在其他一些因素对数据集的模式有贡献。
这总结了 R2 指标可以用来衡量线性模型正确捕捉数据趋势的程度。
摘要
在本章中,我们专注于了解如何衡量我们机器学习模型的性能,以及如何根据哪个模型表现更好来选择一个模型而不是另一个。我们首先从探索 H2O AutoML 排行榜指标开始,因为它们是 AutoML 提供的最容易获得的指标。我们首先介绍了 MSE 和 RMSE 是什么,它们之间的区别是什么,以及它们是如何计算的。然后我们介绍了什么是混淆矩阵,以及如何从混淆矩阵中的值计算准确率、灵敏度、特异性、精确率和召回率。通过我们对灵敏度和特异性的新理解,我们了解了 ROC 曲线和它的 AUC 是什么,以及它们如何被用来直观地衡量不同算法的性能,以及在不同阈值上训练的相同算法的不同模型性能。基于 ROC-AUC 指标,我们探讨了 PR 曲线、它的 AUC 以及它如何克服 ROC-AUC 指标面临的缺点。最后,在排行榜中,我们了解了什么是对数损失,以及我们如何用它来衡量二元分类模型的性能。
然后,我们探索了排行榜之外的一些重要指标,首先是 F1 分数。我们了解了 F1 分数如何将召回率和精确率结合成一个单一指标。然后我们了解了 MCC 以及它如何克服在衡量不平衡数据集时精确率、召回率和 F1 分数的缺点。最后,我们探讨了 R2 指标,它解释了因变量和自变量之间的关系,即自变量变化多少会影响因变量。
带着这些信息,我们现在能够正确地测量和比较模型,以找到解决我们机器学习问题性能最佳的模型。在下一章中,我们将探讨 H2O 提供的各种模型可解释性功能,这些功能提供了关于模型及其特征的详细高级信息。
第七章:使用模型可解释性
模型选择和性能的合理性与模型训练同样重要。您可以使用N个使用不同算法训练的模型,并且所有这些模型都将能够对现实世界问题做出足够好的预测。那么,您如何从它们中选择一个用于生产服务,以及您如何向您的利益相关者证明您选择的模型比其他模型更好,尽管其他模型也能在一定程度上做出准确的预测?一个答案是性能指标,但正如我们在上一章中看到的,有大量的性能指标,并且它们衡量不同类型的性能。选择正确的性能指标归结于您的机器学习问题的上下文。我们还能使用什么来帮助我们选择正确的模型,并进一步帮助我们证明这一选择是合理的?
答案是可视化图表。人类是视觉生物,因此,一张图片胜过千言万语。一个好的图表可以比任何指标数字更好地解释一个模型。图表的多样性在解释模型的行为以及它如何作为我们机器学习问题的解决方案方面非常有用。
H2O 的可解释性界面是一个独特功能,它封装了 H2O 为模型或模型列表自动计算的各种可解释性功能和可视化,包括 H2O AutoML 对象。
在本章中,我们将探讨 H2O 可解释性界面及其与 H2O AutoML 对象的工作方式。我们还将实现一个实际示例,以了解如何在 Python 和 R 中使用可解释性界面。最后,我们将了解并理解我们作为输出获得的所有各种可解释性功能。
本章我们将涵盖以下主要主题:
-
使用模型可解释性界面
-
探索各种可解释性功能
到本章结束时,您应该对如何通过查看模型可解释性界面描述的各种性能指标来解释模型性能有一个很好的了解。
技术要求
对于本章,您需要以下内容:
-
您首选网络浏览器的最新版本。
-
您选择的集成开发环境(IDE)或终端。
-
本章中进行的所有实验都是在终端上进行的。您可以根据相同的设置自由跟随,或者您可以使用您选择的任何 IDE 执行相同的实验。
本章的所有代码示例都可以在 GitHub 上找到,网址为github.com/PacktPublishing/Practical-Automated-Machine-Learning-on-H2O/tree/main/Chapter%207
。
那么,让我们首先了解模型可解释性界面是如何工作的。
使用模型可解释性界面
模型可解释性接口 是一个简单的函数,它包含有关模型及其工作方式的多种图表和信息。H2O 中有两个主要的模型可解释性函数:
-
h2o.explain()
函数,用于解释整个测试数据集中模型的行为。这也被称为 全局解释。 -
h2o.explain_row()
函数,用于解释测试数据集中单个行的模型行为。这也被称为 局部解释。
这两个函数可以在单个 H2O 模型对象、H2O 模型对象列表或 H2O AutoML 对象上工作。这些函数生成一个包含各种图形图表的结果列表,例如 变量重要性图、部分依赖图和 排行榜(如果用于多个模型)。
对于图表和其他视觉结果,explain
对象依赖于可视化引擎来渲染图形:
-
对于 R 接口,H2O 使用
ggplot2
包进行渲染。 -
对于 Python 接口,H2O 使用
matplotlib
包进行渲染。
考虑到这一点,我们需要确保每次我们使用可解释性接口获取视觉图表时,都在支持图形渲染的环境中运行。此接口在终端和其他非图形命令行界面中用处不大。本章中的示例是在 Jupyter Notebook 中运行的,但任何支持绘图渲染的环境都应该可以正常工作。
可解释性函数具有以下参数:
-
newdata
/frame
: 此参数用于指定计算某些可解释性特征(如newdata
)所需的 H2O 测试 DataFrame,而在 Python 可解释性接口中则是frame
。 -
columns
: 此参数用于指定在基于列的解释中要考虑的列,例如 个体条件期望图 或 部分依赖图。 -
top_n_features
: 此参数用于指定基于特征重要性排名进行基于列的解释时需要考虑的列数。默认值为5
。
可解释性函数将考虑 columns
参数或 top_n_features
参数。优先考虑 columns
参数,因此如果两个参数都传递了值,则 top_n_features
将被忽略。
-
include_explanations
: 此参数用于指定您希望从可解释性函数输出中获取的解释。 -
exclude_explanations
: 此参数用于指定您不希望从可解释性函数输出中获取的解释。include_explanations
和exclude_explanations
是互斥参数。这两个参数的有效值如下:-
leaderboard
: 此值仅适用于模型列表或 AutoML 对象。 -
residual_analysis
: 此值仅适用于回归模型。 -
confusion_matrix
:这个值仅对分类模型有效。 -
varimp
:这个值代表变量重要性,仅对基础模型有效,对堆叠集成模型无效。 -
varimp_heatmap
:这个值代表变量重要性的热图。 -
model_correlation_heatmap
:这个值代表模型相关性的热图。 -
shap_summary
:这个值代表 Shapley 加性解释。 -
pdp
:这个值代表部分依赖图。 -
ice
:这个值代表单个条件期望图。
-
-
plot_overrides
:此参数用于覆盖单个解释图的值。如果您想在一个图中考虑前 10 个特征,但在另一个图中考虑特定列,则此参数很有用:list(pdp = list(top_n_features = 8))
-
object
:此参数用于指定 H2O 模型或 H2O AutoML 对象,我们将在稍后介绍。此参数是 R 可解释性接口特有的。
现在我们已经了解了可解释性接口的工作原理及其各种参数,让我们通过一个实现示例来更好地理解它。
我们将使用费舍尔的鸢尾花数据集,我们在第一章,“理解 H2O AutoML 基础知识”中使用它来使用 AutoML 训练模型。然后我们将使用 AutoML 对象上的可解释性接口来显示它提供的所有可解释性特征。
让我们从在 Python 中实现它开始。
在 Python 中实现模型可解释性界面
要在 Python 中实现模型可解释性函数,请按照以下步骤操作:
-
导入
h2o
库并启动本地 H2O 服务器:library(h2o) h2o.init(max_mem_size = "12g")
可解释性界面在后台进行大量计算,以计算绘制图表所需的数据。为了加快处理速度,建议使用尽可能多的内存初始化 H2O 服务器。
-
使用
h2o.importFile(“Dataset/iris.data”)
导入数据集:data = h2o.import_file("Dataset/iris.data")
-
设置哪些列是特征列,哪些列是标签列:
features = data.columns label = "C5"
-
从特征中移除标签:
features.remove(label)
-
将 DataFrame 拆分为训练集和测试集:
train_dataframe, test_dataframe = data.split_frame([0.8])
-
初始化 H2O AutoML 对象:
aml = h2o.automl.H2OAutoML(max_models=10, seed = 1)
-
触发 H2O AutoML 对象,使其开始自动训练模型:
aml.train(x = features, y = label, training_frame = train_dataframe)
-
一旦训练完成,我们就可以使用 H2O 可解释性接口
h2o.explain()
对现在训练好的aml
对象进行操作:aml.explain(test_dataframe)
explain
函数将花费一些时间来完成计算。一旦完成,您应该看到一个列出所有可解释性特征的输出。输出应该如下所示:
图 7.1 – 模型可解释性界面输出
-
您还可以使用
h2o.explain_row()
接口来显示数据集单行的模型可解释性特征:aml.explain_row(test_dataframe, row_index=0)
此输出应为您提供对数据集第一行进行预测的模型的排行榜。
-
要从可解释性角度获取关于模型的更多信息,你可以通过在领先模型上使用
explain_row()
函数进一步扩展可解释性界面,如下所示:aml.leader.explain_row(test_dataframe, row_index=0)
这个输出应该会给出基于该行预测的所有适用的图形模型可解释性功能。
现在我们知道了如何在 Python 中使用模型可解释性界面,让我们看看我们如何在 R 语言中使用这个界面。
在 R 中实现模型可解释性界面
与我们在 Python 中实现可解释性界面类似,H2O 也提供了在 R 编程语言中使用可解释性界面的方法。
要在 R 中实现模型可解释性功能,请按照以下步骤操作:
-
导入
h2o
库并启动本地 H2O 服务器:library(h2o) h2o.init(max_mem_size = "12g")
-
使用
h2o.importFile(“Dataset/iris.data”)
导入数据集:data = h2o.import_file("Dataset/iris.data")
-
将
C5
列设置为标签:label <- "C5"
-
将 DataFrame 分割为训练和测试 DataFrame,并将它们分配给适当的变量:
splits <- h2o.splitFrame(data, ratios = 0.8, seed = 7) train_dataframe <- splits[[1]] test_dataframe <- splits[[2]]
-
运行 H2O AutoML 训练:
aml <- h2o.automl(y = label, training_frame = train_dataframe, max_models = 10)
-
在现在已训练的
aml
对象上使用 H2O 可解释性界面:explanability_object <- h2o.explain(aml, test_dataframe)
一旦可解释性对象完成其计算,你应该会看到一个列出所有可解释性功能的大输出。
-
就像 Python 一样,你还可以扩展模型可解释性界面函数,使其可以通过使用
h2o.explain_row()
函数在单行上运行,如下所示:h2o.explain_row(aml, test, row_index = 1)
这将给出在数据集的第一行上进行预测的模型的排行榜。
-
同样,你可以通过在领先模型上使用
h2o.explain_row()
函数来扩展这个可解释性界面,以获取关于领先模型的更高级信息:h2o.explain_row(aml@leader, test, row_index = 1)
在这些示例中,我们使用了 Iris 花数据集来解决多项分类问题。同样,我们可以在训练好的回归模型上使用可解释性界面。一些可解释性功能仅根据训练模型是回归模型还是分类模型而可用。
现在我们知道了如何在 Python 和 R 中实现模型可解释性界面,让我们更深入地查看界面的输出,并尝试理解 H2O 计算的各种可解释性功能。
探索各种可解释性功能
可解释性界面的输出是一个 H2OExplanation
对象。H2OExplanation
对象不过是带有可解释性功能名称作为键的简单字典。你可以通过使用特征的关键名称作为可解释性对象的 dict
键来检索单个可解释性功能。
如果你向下滚动 H2O AutoML 对象的可解释性界面输出,你会注意到有很多带有解释的标题。在这些标题下面,是对可解释性功能的简要描述。一些包含图形图表,而其他可能包含表格。
各种可解释性功能如下:
-
排行榜:这是一个排行榜,包括所有训练模型及其从最佳性能到最差性能的基本指标。此功能仅在解释性界面在 H2O AutoML 对象或 H2O 模型列表上运行时计算。
-
混淆矩阵:这是一个性能指标,它生成一个矩阵,跟踪分类模型的正确和错误预测。它仅适用于分类模型。对于多个模型,混淆矩阵仅针对领先模型计算。
-
残差分析:此功能在用于解释性界面的测试数据集上绘制预测值与残差的关系。它仅分析基于排行榜模型排名的领先模型。它仅适用于回归模型。对于多个模型,残差分析仅在领先模型上执行。
-
变量重要性:此功能绘制了数据集中变量的重要性。它适用于所有模型,除了堆叠模型。对于多个模型,它仅在领先模型上执行,该模型不是堆叠模型。
-
变量重要性热图:此功能绘制了所有模型中变量重要性的热图。它适用于比较所有模型,除了堆叠模型。
-
模型相关性热图:此功能绘制了不同模型预测值之间的相关性。这有助于将具有相似性能的模型分组在一起。它仅适用于多个模型解释。
-
顶级树模型 SHAP 摘要:此功能绘制了变量在复杂树模型(如随机森林和神经网络)的决策制定中的重要性。此功能为排行榜中排名最高的树模型计算此图。
-
部分依赖多图:此功能绘制了目标特征与数据集中我们认为重要的某些特征集之间的依赖关系。
-
个体条件期望(ICE)图:此功能绘制了目标特征与数据集中我们认为对每个实例单独重要的某些特征集之间的依赖关系。
将此与我们在“使用模型解释性界面”部分进行的实验中从模型解释性界面获得的输出进行比较,您会注意到输出中缺少一些解释性功能。这是因为其中一些功能仅适用于训练的模型类型。例如,残差分析仅适用于回归模型,而我们在“使用模型解释性界面”部分进行的实验是一个分类问题,训练了一个分类模型。因此,您在模型的解释性输出中找不到残差分析。
您可以使用回归问题进行相同的实验;模型可解释性界面将输出回归支持的可解释性特征。
既然我们已经了解了在解释界面中可用的不同可解释性特征,那么让我们逐一深入探讨它们,以深入了解它们的含义。我们将通过我们在 Python 和 R 中实现的可解释性界面的输出进行说明。
在前面的章节中,我们了解了排行榜和混淆矩阵是什么。那么,让我们从下一个解释特征:剩余分析开始。
理解剩余分析
剩余分析是对回归模型进行的。如第五章中所述,“理解 AutoML 算法”部分,在“理解广义线性模型”和“线性回归简介”部分,残差是回归模型预测的值与同一行数据的实际值之间的差异。分析这些残差值是诊断模型中任何问题的绝佳方式。
剩余分析图是你在其中绘制残差值与预测值的图表。我们在第五章中学习到,在“理解广义线性模型”和“理解线性回归的假设”部分,线性回归的一个主要假设是残差的分布是正态分布。
因此,相应地,我们期望我们的残差图是一个无定形的点集。残差值和预测值之间不应有任何模式。
剩余分析可以突出训练模型中异方差性的存在。如果预测值的标准差在不同特征值上发生变化,则称为发生了异方差性。
考虑以下图表:
图 7.2 – 同方差数据集的回归图
上述图表显示了一个回归图,其中我们有一些样本数据,这些数据映射了X和Y之间的关系。让我们通过这些数据拟合一条直线,这代表我们的线性模型。如果我们从X轴的左侧到右侧计算每个点的残差,我们会注意到误差率在整个X值的范围内保持相对恒定。这意味着所有误差值都位于平行蓝色线之间。在整个独立变量中,误差或残差的分布保持恒定的情况称为同方差性。
同方差性的相反面是异方差性。这是指误差率随着X值的变化而变化。参考以下图表:
图 7.3 – 异方差数据集的回归图
如您所见,线性模型所犯错误的幅度随着 X 的增加而增加。如果你绘制包含所有错误的蓝色误差线,那么你会注意到它们逐渐扩散开来,并且不是平行的。这种在整个自变量中误差或残差分布不恒定的情况称为异方差性。
异方差性告诉我们,模型未能捕捉和学习的某些信息。异方差性也违反了线性回归的基本假设。因此,它可以帮助你确定你可能需要将缺失信息添加到你的数据集中以正确训练你的线性模型,或者你可能需要实现一些非线性回归算法以获得性能更好的模型。
由于残差分析是回归特定的模型可解释性特征,我们不能使用我们在“使用模型可解释性界面”部分进行的 Iris 数据集分类实验。相反,我们需要训练一个回归模型,然后在该模型上使用模型可解释性界面来获取残差分析输出。因此,让我们看看使用红葡萄酒质量数据集的回归问题。您可以在archive.ics.uci.edu/ml/datasets/wine+quality
找到这个数据集。
这个数据集包括以下特征:
-
固定酸度: 这个特征解释了非挥发性酸度的含量,意味着它不会在一段时间内蒸发。
-
挥发性酸度: 这个特征解释了挥发性酸度的含量,意味着它会在一段时间内蒸发。
-
柠檬酸: 这个特征解释了葡萄酒中存在的柠檬酸含量。
-
残余糖分: 这个特征解释了葡萄酒中存在的残余糖分含量。
-
氯化物: 这个特征解释了葡萄酒中存在的氯化物数量。
-
游离二氧化硫: 这个特征解释了葡萄酒中存在的游离二氧化硫含量。
-
总二氧化硫: 这个特征解释了葡萄酒中存在的总二氧化硫含量。
-
密度: 这个特征解释了葡萄酒的密度。
-
pH 值: 这个特征解释了葡萄酒的 pH 值,其中 0 表示最酸,14 表示最碱。
-
硫酸盐: 这个特征解释了葡萄酒中存在的硫酸盐数量。
-
酒精含量: 这个特征解释了葡萄酒中存在的酒精含量。
-
质量: 这是响应列,表示葡萄酒的质量。0 表示葡萄酒非常差,而 10 表示葡萄酒非常好。
我们将运行我们的基本 H2O AutoML 流程来训练模型,然后使用训练好的 AutoML 对象上的模型可解释性界面来获取残差分析图。
现在,让我们观察从这个实现中得到的残差分析图,然后看看我们如何从图中检索所需的信息。参考以下图表:
图 7.4 – 红酒质量数据集的残差分析图
在这里,你可以看到堆叠集成模型的残差分析,这是 AutoML 训练模型的领导者。在X轴上,你有拟合值,也称为预测值,而在Y轴上,你有残差。
在Y轴的左侧和X轴下方,你会看到一个灰度列和一个行,分别。这些帮助你观察这些残差在X和Y轴上的分布。
为了确保残差的分布是正态的,并且数据不是异方差性的,你需要观察Y轴上的这个灰度。理想的正态分布会给你一个在中心最暗,向外逐渐变亮的灰度。
现在你已经了解了如何解读残差分析图,让我们进一步学习下一个可解释性特征:变量重要性。
理解变量重要性
变量重要性,也称为特征重要性,正如其名,解释了数据集中不同变量/特征在预测中的重要性。在任何机器学习问题中,你的数据集通常会有多个变量,这些变量会影响你的预测列的特征。然而,在大多数情况下,你通常会有一些特征比其他特征贡献更多。
这种理解可以帮助科学家和工程师从数据集中移除任何引入噪声的不需要的特征。这可以进一步提高模型的质量。
H2O 为不同类型的算法计算变量重要性不同。首先,让我们了解变量重要性是如何在基于树的算法中计算的。
基于树的算法中的变量重要性是根据两个标准计算的:
-
决策树变量选择
-
由于选择而导致的整个树上的平方误差改进
每当 H2O 在训练基于树的模型时构建决策树,它将使用一个特征作为节点来进一步分割树。正如我们在第五章“理解 AutoML 算法”部分所研究的,在“理解分布式随机森林算法”部分,我们知道决策树中的每个节点分割都旨在减少整体平方误差。这个扣除的值就是父节点与子节点平方误差之间的差异。
H2O 在计算特征重要性时考虑了平方误差的减少。基于树的模型中每个节点的平方误差导致该节点的响应值方差降低。
因此,相应地,计算树平方误差的方程如下:
这里,我们有以下内容:
-
MSE 表示均方误差
-
N 表示观测值的总数
-
VAR 表示方差
计算方差的公式如下:
这里,我们有以下内容:
-
表示观测值的数值
-
表示所有观测值的平均值
-
N 表示观测值的总数
对于基于树的集成算法,如 梯度提升算法(GBM),决策树是顺序训练的。每一棵树都是建立在上一棵树的错误之上的。因此,特征重要性计算与我们在单个决策树中的单个节点计算相同。
对于 分布式随机森林(DRF),决策树是并行训练的,因此 H2O 只是平均结果来计算特征重要性。
对于 XGBoost,H2O 在构建树时,从单个特征的损失函数增益中计算特征重要性。
对于 深度学习,H2O 使用一种称为 Gedeon 方法 的特殊方法来计算特征重要性。
对于 广义线性模型(GLMs),变量重要性与预测权重相同,也称为系数幅度。如果在训练过程中,你决定标准化数据,则返回标准化系数。
以下图表显示了我们对爱丽丝花数据集进行的实验中计算的特征重要性:
图 7.5 – 爱丽丝花数据集的变量重要性图
上述图表显示了深度学习模型的变量重要性图。如果你与你的排行榜进行比较,你会看到变量重要性图是为最领先的模型绘制的,这并不是一个堆叠集成模型。
在图表的 Y 轴上,你有特征名称 – 在我们的案例中,是爱丽丝花数据集的 C1、C2、C3 和 C4 列。在 X 轴上,你有这些变量的重要性。可以得到特征重要性的原始指标值,但 H2O 通过将其缩放到 0 到 1 之间来显示重要性值,其中 1 表示最重要的变量,而 0 表示最不重要的变量。
由于变量重要性对分类和回归模型都可用,你也会在红酒质量回归模型的可解释性功能中获得一个变量重要性图。图表应该如下所示:
图 7.6 – 红酒质量数据集的变量重要性图
现在你已经了解了如何解释特征重要性图,让我们来理解特征重要性热图。
理解特征重要性热图
当显示特定模型的特征重要性时,将其表示为直方图或条形图相对容易。然而,我们经常需要比较不同模型的特征重要性,以便了解哪个模型认为哪些特征是重要的,以及我们如何利用这些信息来比较模型性能。H2O AutoML 会自动训练多个具有不同机器学习算法的模型。因此,对模型性能的比较是必不可少的,而特征重要性的图形表示对科学家和工程师来说非常有帮助。
为了在单个图表中表示 H2O AutoML 训练的所有模型的特征重要性,H2O 生成一个特征重要性热图。
热图是一种数据可视化图表,其中图表的颜色受特定值的密度或大小的影响。
一些 H2O 模型会在分类列的编码版本上计算变量重要性。不同的模型也有不同的编码分类值的方式。因此,比较所有模型中这些分类列的变量重要性可能会很棘手。H2O 通过汇总所有特征上的变量重要性,并返回一个代表原始分类特征的单一变量重要性值来完成这个比较。
以下是为鸢尾花数据集实验生成的特征重要性热图:
图 7.7 – 变量重要性热图
在这里,我们可以看到排行榜上排名前 10 的模型。
热图在 Y 轴上具有C1、C2、C3和C4特征,而在 X 轴上则是模型 ID。图表的颜色表示模型在预测过程中认为特征的重要程度。重要性越高,价值越大,相应的图表就会变成红色。重要性越低,特征的重要性值就越低;颜色会变得更冷,变成蓝色。
现在你已经了解了如何解释特征重要性热图,让我们来学习模型相关性热图。
理解模型相关性热图
多个模型之间另一个重要的比较是模型相关性。模型相关性可以理解为当你比较它们的预测值时,模型在性能上的相似程度。
如果一个模型做出的预测与另一个模型做出的预测相同或相似,那么使用相同或不同机器学习算法训练的不同模型被认为是高度相关的。
在模型相关性热图中,H2O 比较了它所训练的所有模型的预测值,并将它们相互比较。
以下是我们从鸢尾花数据集实验中得到的模型相关性热图:
图 7.8 – 鸢尾花数据集的模型相关性热图
小贴士
要了解这个可解释性特征图,请参考您在代码中执行 explain()
函数后得到的输出中的 模型相关性 部分。
在 X 和 Y 轴上,我们有模型 ID。它们在图上的截面表示它们之间的相关性值。您会注意到图上 X 和 Y 轴之间的热点具有相同的模型 ID,这始终是 1;因此,图表始终是红色的。这是正确的,因为技术上它们是同一个模型,当您比较一个模型的预测值与自身的预测值时,会有 100% 的相关性。
要更好地了解不同模型之间的相关性,您可以参考这些热值。深红色点表示高度相关,而那些具有凉爽蓝色值的点表示低相关性。用红色突出显示的模型是可解释模型,如 GLM。
您可能会注意到,由于模型相关性热图支持堆叠集成模型,而特征重要性热图不支持,如果您忽略模型相关性热图(图 7.8)中的堆叠集成模型,其余的模型与特征重要性热图(图 7.7)中的模型相同。
现在您已经知道了如何解释模型相关性热图,让我们再来了解部分依赖图。
理解部分依赖图
部分依赖图(PDP)是一个图表,展示了在边际化我们不感兴趣的输入特征值的情况下,预测值与我们感兴趣的输入特征集之间的依赖关系。
另一种理解 PDP 的方法是,它表示了一个输入特征的函数,该函数给出了预期的预测值作为输出。
PDP 是一个非常有趣的图表,有助于向那些不太擅长数据科学领域的组织成员展示和解释模型训练结果。
在学习如何计算它之前,让我们先了解如何解释一个 DPD。以下是我们使用鸢尾花数据集进行实验时得到的 PDP 图:
图 7.9 – 以 Iris-setosa 为目标的 C1 列的 PDP
小贴士
要理解这个可解释性特征图,请参考您在代码中执行explain()
函数后得到的输出中的部分依赖图部分。
PDP 图是一个显示特征对响应值边际效应的图表。在图表的X轴上,您有选定的特征及其值范围。在Y轴上,您有目标值的平均响应值。PDP 图旨在告诉观众模型对选定特征的给定值预测的平均响应值。
在图 7.9中,PDP 图是为目标值Iris-setosa的C1列绘制的。在X轴上,我们有C1列,代表花的萼片长度(以厘米为单位)。这些值的范围从数据集中的最小值到最大值。在Y轴上,我们有平均响应值。对于这个实验,平均响应值是花是 Iris-setosa 的概率,这是图表选定的目标值。图上的彩色线条表示 H2O AutoML 为C1值范围预测的不同模型预测的平均响应值。
观察这个图表能让我们很好地了解响应值如何依赖于每个模型的单个特征,C1。我们可以看到,只要花瓣的萼片长度在 4.5 到 6.5 厘米之间,大多数模型显示的近似概率是花属于 Iris-setosa 类的可能性有 35%。
类似地,在下面的图表中,我们绘制了C1列的 PDP 图,但这次的目标响应列是Iris-versicolor:
图 7.10 – 以 Iris-versicolor 为目标列的 PDP 图
小贴士
要理解这个可解释性特征图,请参考您在代码中执行explain()
函数后得到的输出中的部分依赖图部分。
在这里,我们可以看到,只要C1的值在 4.5 到 6.5 之间,花属于 Iris-versicolor 类的可能性大约在 27%到 40%之间。现在,让我们看看以下针对C1的第三个目标值,Iris-virginica的 PDP 图:
图 7.11 – 以 Iris-virginica 为目标列的 PDP 图
小贴士
为了更好地理解这个可解释性特征图,请参考您在代码中执行explain()
函数后得到的输出中的部分依赖图部分。
您会注意到,对于Iris-virginica,所有模型对相同的C1值预测不同。这可能意味着Iris-virginica类并不强烈依赖于花的萼片长度,即C1值。
PDP 可能还有助于模型选择。假设你确信你的数据集中某个特定特征将对响应值产生很大贡献,并且你针对它训练了多个模型。然后,你可以选择最适合这种关系的模型,因为这个模型将做出最真实准确的预测。
现在,让我们尝试理解 PDP 图是如何生成的,以及 H2O 是如何计算这些绘图值的。
PDP 图数据可以按以下方式计算:
-
选择一个特征和目标值来绘制依赖关系。
-
从验证数据集中自助生成一个数据集,其中所选特征的值设置为验证数据集中所有行的最小值。
-
将此自助数据集传递给由 H2O AutoML 训练的其中一个模型,并计算它对所有行的预测值的平均值。
-
将此值绘制在该模型的 PDP 图上。
-
对剩余的模型重复步骤 3和步骤 4。
-
重复步骤 2,但这次,将所选特征的值增加到验证数据集中存在的下一个值。然后,重复剩余的步骤。
你将对验证数据集中所有特征值进行此操作,并将它们绘制在所有模型的同一 PDP 图上。
完成后,你将对特征和目标响应值的组合进行不同的操作。
H2O 将为所有特征和响应值的组合创建多个 PDP 图。以下是一个 PDP 图,其中所选特征是C2,所选目标值是Iris-setosa:
图 7.12 – 以 Iris-setosa 为目标列的 C2 列 PDP 图
小贴士
为了更好地理解这个可解释性特征图,请参考你在代码中执行explain()
函数后得到的输出中的部分依赖性图部分。
类似地,它为C3和C4特征创建了不同的 PDP 图组合。以下是一个 PDP 图,其中所选特征是C3,所选目标值是Iris-versicolor:
图 7.13 – 以 Iris-versicolor 为目标列的 PDP 图
小贴士
为了更好地理解这个可解释性特征图,请参考你在代码中执行explain()
函数后得到的输出中的部分依赖性图部分。
现在你已经知道如何解释特征重要性热图,让我们来了解 SHAP 摘要图。
理解 SHAP 摘要图
对于复杂的问题,基于树的模型可能难以理解。复杂的树模型可能非常大且难以理解。SHAP 摘要图是基于树的模型的简化图,它为你提供了一个模型复杂性和行为的概述视图。
SHAP代表Shapley Additive Explanations。SHAP 是一种模型可解释性特征,它采用博弈论的方法来解释机器学习模型的输出。SHAP 摘要图显示了特征对预测值的贡献,类似于 PDPs。
让我们尝试从一个例子中解释 SHAP 值。以下是从红葡萄酒质量数据集中得到的 SHAP 摘要:
图 7.14 – 红葡萄酒质量数据集的 SHAP 摘要图
小贴士
为了更好地理解这个可解释性特征图,请参考执行回归模型的explain()
函数后得到的输出中的SHAP 摘要部分。
在右侧,你可以看到一个蓝红色条形。这个条形表示葡萄酒质量的归一化值,用颜色表示。颜色越红,质量越好;颜色越蓝,葡萄酒质量越差。在二项问题中,颜色将在红色和蓝色之间形成鲜明对比。然而,在我们的例子中,回归问题,我们可以有一个完整的颜色光谱,表示可能的数值范围。
在Y轴上,你有数据集中的特征。它们根据特征的重要性从上到下按降序排列。在我们的例子中,酒精含量是数据集中最重要的特征;它对最终预测值的影响更大。
在X轴上,你有SHAP 值。SHAP 值表示特征如何帮助模型达到预期的结果。SHAP 值越正,该特征对结果的影响就越大。
让我们以 SHAP 摘要中的酒精为例。基于此,我们可以看到酒精在所有其他特征中具有最高的 SHAP 值。因此,酒精对模型的预测贡献很大。此外,具有最高 SHAP 值的酒精在图中的点用红色表示。这也表明高酒精含量有助于产生积极的结果。考虑到这一点,我们可以从这张图中提取的信息是,特征酒精含量在预测葡萄酒质量方面起着重要作用,而且酒精含量越高,葡萄酒的质量越好。
同样,你也可以从其他特征中解释相同的知识。这可以帮助你比较和理解哪些特征是重要的,以及它们如何对模型的最终预测做出贡献。
关于 SHAP 摘要和 PDP 的一个有趣的问题是,它们之间有什么区别?嗯,这两个之间的主要区别是,PDP 解释了仅替换一个特征对输出的影响,而 SHAP 摘要考虑了该特征与数据集中其他特征的总体交互。因此,PDP 基于你的特征相互独立的假设,而 SHAP 则考虑了不同特征的组合贡献及其对总体预测的综合影响。
计算 SHAP 值是一个复杂的过程,它源于博弈论。如果你对扩展你的博弈论知识以及 SHAP 值是如何计算的感兴趣,请随时以自己的节奏探索。理解 SHAP 的一个好起点是遵循 https://shap.readthedocs.io/en/latest/index.xhtml 上的解释。在撰写本文时,H2O 充当 SHAP 库的包装器,并在内部使用此库来计算 SHAP 值。
现在我们已经知道了如何解释 SHAP 摘要图,让我们来了解可解释性特征,单个条件期望(ICE)图。
理解单个条件期望图
ICE图是一个显示每个观察实例的线图的图表,它显示了当特征值变化时给定观察的预测如何变化。
ICE 图类似于 PDP 图。PDP 关注特征变化对预测结果的整体平均影响,而 ICE 图关注结果对特征值单个实例的依赖性。如果你平均 ICE 图值,你应该得到一个 PDP。
计算 ICE 图的方法非常简单,如下截图所示:
图 7.15 – ICE 图绘制示例数据集突出显示观察到 1
一旦你的模型已经训练好,你必须执行以下步骤来计算 ICE 图:
-
考虑第一个观察 – 在我们的例子中,观察到 1 – 并绘制特征 1与相应的目标值之间的关系。
-
保持特征 1的值不变,创建一个引导数据集,同时将所有其他特征值替换为原始数据集中观察到 1中看到的值;将所有其他观察标记为观察到 1。
-
使用你的训练模型计算观察的目标值。
参考以下截图以获取引导数据集:
图 7.16 – 观察到 1 的 1 号特征的引导数据集
- 对下一个观察重复相同的操作。考虑第二个观察 – 在我们的例子中,观察到 2 – 并绘制特征 1与相应的目标值之间的关系:
图 7.17 – 强调观察 2 的样本数据集的 ICE 图
- 保持特征 1的值不变,创建一个自举数据集;然后,使用训练好的模型计算目标值。参考以下生成的自举数据集:
图 7.18 – 特征 1 的观察 2 的自举数据集
-
我们对所有观察结果和所有特征重复此过程。
-
从这些自举数据集中观察到的结果绘制在每个特征的单独 ICE 图上。
让我们看看如何解释 ICE 图并从中提取可观察的信息。参考以下截图,它显示了在训练在红酒质量数据集上的 AutoML 对象上运行模型可解释性界面后得到的 ICE 图:
图 7.19 – 红酒质量数据集的 ICE 图
如标题所述,这是一个 H2O AutoML 训练的堆叠集成模型的酒精特征列的 ICE 图。请注意,这个模型是 AutoML 训练的模型列表中的领导者。ICE 图只为数据集的领导者绘制。您还可以通过提取具有其模型 ID 的其他模型并对其运行ice_plot()
函数来观察其他模型的 ICE 图。参考以下代码示例:
model = h2o.get_model("XRT_1_AutoML_2_20220516_64004")
model.ice_plot(test_dataframe, "alcohol")
在图表的X轴上,有酒精特征的值范围。在Y轴上,有预测结果的值范围——即葡萄酒的质量。
在图表的左侧,您可以看到说明不同类型线条及其百分位数的图例。ICE 图绘制了每个十分位的效果。所以,从技术上讲,在绘制 ICE 图时,您为每个观察结果计算一条线。然而,在一个包含数千行甚至数百万行数据的数据集中,您将在图表上得到相等数量的线条。这将使 ICE 图变得混乱。这就是为什么为了更好地观察这些数据,您必须将线条聚合到最近的十分位,并为每个百分位数分区绘制一条单独的线条。
点状黑色线是所有这些其他百分位数线的平均值,也就是该特征的 PDP 线。
现在您已经知道如何解释 ICE 图,让我们看看学习曲线图。
理解学习曲线图
学习曲线图是数据科学家观察模型学习率最常用的图表之一。学习曲线显示了模型如何从数据集中学习以及它学习的效率。
当处理一个机器学习问题时,一个经常需要回答的重要问题是,“我们需要多少数据来训练最准确的模型?”学习曲线图可以帮助您了解增加数据集如何影响您的整体模型性能。
使用这些信息,您可以决定增加数据集的大小是否会导致更好的模型性能,或者您是否需要改进模型训练以提高模型性能。
让我们观察我们从红葡萄酒质量数据集上的 XRT 模型训练实验中获得的学习曲线图:
图 7.20 – 在红葡萄酒质量数据集上的 XRT 模型学习曲线图
在图表的 X 轴上,您有 XRT 算法创建的树的数量。如您所见,该算法总共创建了大约 40 到 50 棵树。在 Y 轴上,您有性能指标 RMSE,这是在算法创建树的过程中在每个阶段计算的。
如前一张截图所示,随着算法创建更多的树,RMSE 指标逐渐降低。最终,在创建了一定数量的树之后,RMSE 降低的速度会逐渐减慢。超过这个数量创建的树不会对模型性能的整体提升做出贡献。因此,随着树的数量增加,学习率最终会降低。
图表上的线条描述了算法在训练过程中使用的各种数据集以及在每个创建树实例中的相应 RMSE。
在撰写本文时,截至 H2O 版本3.36.1,学习曲线图不是默认模型可解释性界面的一部分。要绘制学习曲线,您必须使用以下函数在相应的模型对象上绘制:
model = h2o.get_model("GLM_1_AutoML_2_20220516_64004")
model.learning_curve_plot()
不同算法的学习曲线图是不同的。以下截图显示了在相同数据集上由 AutoML 训练的 GLM 模型的学习图:
图 7.21 – 在红葡萄酒质量数据集上的 GLM 模型学习曲线图
如您所见,现在在 X 轴上不再是树的数量,而是迭代次数。树的数量对于基于树的算法(如 XRT 和 DRF)是相关的,但运行在线性算法上的线性模型(如 GLM)更有助于学习。在 Y 轴上,您有偏差而不是 RMSE,因为偏差更适合衡量线性模型的表现。
学习曲线对于不同类型的算法是不同的,包括堆叠集成模型。您可以自由探索不同算法的学习曲线的不同变体。H2O 已经根据算法选择合适的性能指标和学习步骤,因此您不必担心是否选择了正确的指标来衡量学习率。
摘要
在本章中,我们专注于理解 H2O 提供的模型可解释性界面。首先,我们了解了可解释性界面如何提供不同的可解释性功能,帮助用户获取关于训练模型的详细信息。然后,我们学习了如何在 H2O 的 AutoML 训练的模型上实现这一功能,无论是使用 Python 还是 R。
一旦我们对其实施感到满意,我们就开始探索和理解可解释性界面输出显示的各种可解释性图表,从残差分析开始。我们观察到残差分析如何帮助突出数据集中的异方差性,以及它是如何帮助您识别数据集中是否存在任何缺失信息的。
然后,我们探讨了变量重要性以及它是如何帮助您识别数据集中的重要特征的。在此基础上,我们学习了特征重要性热图如何帮助您观察 AutoML 训练的所有模型中的特征重要性。
然后,我们发现如何解释模型相关性热图,以及它们如何帮助我们识别从模型列表中具有相似预测行为的模型。
之后,我们学习了 PDP 图以及它们如何表达整体结果对数据集个别特征的依赖性。带着这些知识,我们探索了 SHAP 摘要和 ICE 图,我们了解了这两张图以及它们如何分别关注结果对个别特征的依赖性的不同方面。
最后,我们探讨了学习曲线是什么以及它是如何帮助我们理解模型在观察次数、迭代或树的数量上的性能改进,也称为学习,这取决于训练模型所使用的算法类型。
在下一章中,我们将运用从前几章学到的所有知识,探索在使用 H2O 的 AutoML 功能时可以使用的其他高级参数。
第三部分 H2O AutoML 高级实现与产品化
这一部分将帮助您了解 H2O AutoML 的高级特性和参数,这些参数用于定制 AutoML 的某些特性以适应特定需求。这将帮助您获得通用机器学习无法提供的个性化结果。它还将解释 H2O AutoML 如何与不同类型的技术一起使用,您将了解如何将您的机器学习模型部署到生产环境中,并商业性地使用它们来满足业务需求。
本节包括以下章节:
-
第八章, 探索 H2O AutoML 的可选参数
-
第九章, 探索 H2O AutoML 中的其他功能
-
第十章, 与普通 Java 对象(POJOs)一起工作
-
第十一章, 与模型对象优化(MOJO)一起工作
-
第十二章, 使用 H2O AutoML 和 Apache Spark
-
第十三章, 使用 H2O AutoML 与其他技术
第八章:探索 H2O AutoML 的可选参数
正如我们在第二章中探讨的,使用 H2O Flow(H2O 的 Web UI),当使用 H2O AutoML 训练模型时,我们有大量的参数可供选择。所有这些参数都赋予我们控制 H2O AutoML 如何训练我们的模型的能力。这种控制帮助我们根据我们的需求获得 AutoML 的最佳使用效果。我们探讨的大多数参数都很容易理解。然而,有些参数的目的和效果在本书一开始时理解起来稍微复杂一些。
在本章中,我们将通过了解其背后的机器学习(ML)概念来探索这些参数,然后了解我们如何在 AutoML 环境中使用它们。
到本章结束时,您不仅将了解一些高级 ML 概念,而且还将能够使用 H2O AutoML 中提供的参数规定来实现它们。
本章将涵盖以下主题:
-
尝试支持不平衡类别的参数
-
尝试支持提前停止的参数
-
尝试支持交叉验证的参数
我们将首先了解不平衡类别的概念。
技术要求
完成本章内容您需要以下条件:
-
您首选的网页浏览器的最新版本。
-
安装在您系统上的 H2O 软件。有关如何在您的系统上安装 H2O 的说明,请参阅第一章,理解 H2O AutoML 基础知识。
小贴士
本章中展示的所有 H2O AutoML 函数参数均使用 H2O Flow 进行展示,以保持内容简洁。等效参数也以 Python 和 R 编程语言的形式提供,供软件工程师将其编码到他们的服务中。您可以在docs.h2o.ai/h2o/latest-stable/h2o-docs/parameters.xhtml
找到这些详细信息。
尝试支持不平衡类别的参数
在 ML 领域,您经常会遇到的一个常见问题是分类罕见事件。考虑大地震的例子。每年大约发生一次 7 级以上的大地震。如果您有一个包含过去十年每天地球板块活动的数据集,其中响应列包含是否发生地震,那么您将有大约 3,650 行数据;也就是说,十年中的每一天一行,大约有 8-12 行显示大地震。这个事件发生的概率不到 0.3%。99.7%的时间,不会有大地震。这个大型地震事件数量如此之小的数据集被称为不平衡数据集。
不平衡数据集的问题在于,即使你编写一个简单的if-else
函数来标记所有构造事件为非地震,并将其称为模型,它仍然会显示 99.7%的准确率,因为大多数事件都不是地震引起的。然而,实际上,这个所谓的模型非常糟糕,因为它没有正确地告诉你是否是地震。
这种在目标类中的不平衡会在训练机器学习模型时造成很多问题。机器学习模型更有可能假设这些事件非常罕见,永远不会发生,并且不会学习这些事件之间的区别。
然而,有方法可以解决这个问题。一种方法是对多数类进行下采样,另一种方法是对少数类进行过采样。我们将在接下来的章节中了解更多关于这些技术的内容。
理解对多数类进行下采样的方法
在预测地震发生的情况中,数据集中包含大量已被识别为非地震的事件。这个事件被称为多数类。标记活动为地震的少数事件被称为少数类。
让我们看看对多数类进行下采样如何解决由类别不平衡引起的问题。考虑以下图表:
图 8.1 – 对不平衡数据集进行下采样
假设你拥有 3,640 个表示没有发生地震的构造活动数据样本,以及仅 10 个表示发生地震的样本。在这种情况下,为了解决这种不平衡问题,你必须创建一个包含所有 10 个少数类样本,以及从 3,640 个数据样本中随机选择的 10 个多数类样本的 bootstrapped 数据集。然后,你可以将这个新的数据集输入到 H2O AutoML 中进行训练。在这种情况下,我们在训练模型之前对多数类进行了下采样,并平衡了地震和非地震数据样本。
这种方法的缺点是我们最终会丢弃大量数据,并且模型无法从减少的数据中学习到很多。
理解对少数类进行过采样的方法
解决不平衡数据集问题的第二种方法是对少数类进行过采样。一种明显的方法是将少数类数据样本复制并附加到数据集中,使得多数类和少数类之间的数据样本数量相等。参考以下图表以获得更好的理解:
图 8.2 – 对不平衡数据集进行过采样
在前面的图表中,你可以看到我们复制了少数类数据样本并将它们附加到数据集中,结果每个类别都有 3,640 行。
这种方法可以工作;然而,过采样会导致数据集大小的爆炸性增长。你需要确保它不会超过你的计算和内存限制,否则最终会失败。
现在我们已经介绍了使用欠采样和过采样进行类别平衡的基本知识,让我们看看 H2O AutoML 是如何使用其类别平衡参数来处理它的。
在 H2O AutoML 中处理类别平衡参数
H2O AutoML 有一个名为balance_classes
的参数,它接受一个布尔值。如果设置为True,H2O 将对少数类进行过采样,对多数类进行欠采样。平衡是按照这样的方式进行的,最终每个类别都包含相同数量的数据样本。
对相应类别的欠采样和过采样都是随机进行的。此外,少数类的过采样是带替换的。这意味着可以从少数类中选择数据样本并将其多次添加到新的训练数据集中,并且可以重复。
H2O AutoML 有以下参数支持类别平衡功能:
balance_classes
:此参数接受一个布尔值。默认为False,但如果你想在将数据集输入 H2O AutoML 进行训练之前进行类别平衡,则可以将布尔值设置为True。
在 H2O Flow 中,你会在参数旁边得到一个复选框。请参考以下截图:
图 8.3 – H2O Flow 中的 balance_classes 复选框
选中它会使class_sampling_factors
和max_after_balance_size
参数在运行 AutoML参数的专家部分中可用,如下截图所示:
图 8.4 – 专家部分中的 class_sampling_factors 和 max_after_balance_size 参数
-
class_sampling_factors
:此参数要求balance_classes
为True。此参数接受一个浮点数列表作为输入,该列表将代表该类的采样率。对于给定类的值为1.0的采样率将在类别平衡期间不改变其采样率。采样率为0.5将使类别在类别平衡期间的采样率减半,而采样率为2.0将使其加倍。 -
max_after_balance_size
:此参数要求balance_classes
为True,并指定平衡后的训练数据集的最大相对大小。此参数接受一个float
值作为输入,这将限制你的训练数据集可以增长的大小。默认值是5.0,表示训练数据集将增长到其大小的最大5倍。此值也可以小于1.0。
在 Python 编程语言中,你可以这样设置这些参数:
aml = h2o.automl.H2OAutoML(balance_classes = True, class_sampling_factors =[0.3, 2.0], max_after_balance_size=0.95, seed = 123)
aml.train(x = features, y = label, training_frame = train_dataframe)
类似地,在 R 编程语言中,你可以这样设置这些参数:
aml <- h2o.automl(x = features, y = label, training_frame = train_dataframe, seed = 123, balance_classes = TRUE, class_sampling_factors = c(0.3, 2.0), max_after_balance_size=0.95)
在使用 AutoML 训练模型进行类别平衡时,你可以在 H2O AutoML 估计器对象中将balance_classes
参数设置为 true。在同一个对象中,你可以指定你的class_sampling_factors
和max_after_balance_size
参数。然后,你可以使用这个初始化的 AutoML 估计器对象来在你的训练数据集上触发 AutoML。
现在你已经了解了如何使用balance_classes
、class_sampling_factors
和max_after_balance_size
参数来解决类别不平衡问题,让我们了解 AutoML 中的下一个可选参数——那就是停止标准。
尝试支持提前停止的参数
过拟合模型是在尝试解决机器学习问题时经常遇到的一个常见问题。当机器学习模型试图过度适应训练集时,就会发生过拟合,以至于它只能对训练集中之前见过的值做出预测,而无法对未见过的数据进行泛化预测。
过拟合是由于多种原因造成的,其中之一是模型从数据集中学习得太多,以至于它甚至吸收并学习了数据集中的噪声。这种学习对可能没有那种噪声的新数据的预测产生了负面影响。那么,我们如何解决这个问题并防止模型过拟合呢?在模型学习噪声之前尽早停止模型。
在接下来的子节中,我们将了解什么是提前停止以及它是如何实现的。然后,我们将学习 H2O AutoML 提供的提前停止参数是如何工作的。
理解提前停止
提前停止是一种正则化形式,一旦模型对数据有了令人满意的了解,就会停止模型的训练,并进一步防止它过拟合。提前停止旨在通过使用适当的性能指标观察模型性能的改善,一旦观察到由于过拟合导致的性能下降,就停止模型的训练。
当使用迭代优化最小化损失函数的算法训练模型时,训练数据集会在每次迭代中通过算法。然后,通过观察和理解这些数据,在下一个迭代中使用。这种将训练数据集通过算法的迭代过程称为一个 epoch。
对于提前停止,在每个 epoch 结束时,我们可以计算模型的表现并记录指标值。在每次迭代中比较这些值有助于我们了解模型是否在每个 epoch 后提高了性能,或者它是否在学习噪声并失去性能。我们可以监控这一点,并在性能开始下降的 epoch 停止模型训练。参考以下图表以更好地理解提前停止:
图 8.5 – 避免模型过拟合的提前停止
在前面的图中,Y轴上我们有模型的性能值。在X-轴上,我们有Epoch值。因此,随着时间的推移,我们遍历 epoch 的数量,我们看到模型在训练集和验证集上的性能持续增加。但经过某个点后,模型在验证数据集上的性能开始下降,而训练数据集的性能继续增加。这就是过拟合开始的地方。模型从训练数据集中学习得太多,并开始将其学习中的噪声纳入其中。这可能在训练数据集上显示出高性能,但模型无法泛化预测。这导致对未见数据(如验证数据集中的数据)的预测不佳。
因此,最好的做法是在模型性能在训练和验证数据集上最高的确切点停止模型。
现在我们已经对模型训练早期停止的工作原理有了基本了解,接下来让我们学习如何使用 H2O AutoML 函数提供的早期停止参数来执行它。
在 H2O AutoML 中处理早期停止参数
H2O AutoML 为您提供了实施和控制它将为您自动训练的模型早期停止的选项。
您可以使用以下参数来实现早期停止:
-
stopping_rounds
:此参数表示在停止指标未能改善的情况下,我们停止模型训练的训练轮数。 -
stopping_metric
:此参数用于选择在早期停止时考虑的性能指标。如果stopping_rounds
被设置并且大于0,则此参数可用。我们在第六章,“理解 H2O AutoML 排行榜和其他性能指标”中研究了性能指标,如果您想复习不同指标如何衡量性能,请参阅该章节。此参数的可用选项如下:-
AUTO
:这是默认值,并且根据机器学习问题的类型进一步默认为以下值:-
logloss
:分类问题的默认停止指标。 -
deviance
:回归问题的默认停止指标。这代表平均残差偏差。 -
anomaly_score
:Isolation Forest 模型(集成模型)的默认停止指标。
-
-
anomaly_score
:Isolation Forest 模型(集成模型)的默认停止指标。它是观察正常性的度量,相当于在决策树中隔离给定树中某点的最大深度所需的分割数。 -
deviance
:这代表平均残差偏差。此值告诉我们,基于数据集中的特征数量,模型可以有多好地预测标签值。 -
logloss
:Log loss 是一种衡量输出概率值形式的分类模型性能的指标。 -
MSE
(RMSE
(MAE
(RMSLE
(AUC
(AUCPR
(lift_top_group
:此参数配置 AutoML,使得正在训练的模型必须在训练数据的前 1%内提高其提升度。提升度不过是衡量模型在做出准确预测方面的性能,与随机预测的模型相比。数据集的前 1%是具有最高预测值的观测值。 -
misclassification
:此指标用于衡量预测错误的预测比例,不区分正负预测。 -
mean_per_class_error
:这是一个指标,它计算包含多个类别的数据集中每类的所有错误的平均值。 -
custom
:此参数用于在 AutoML 训练期间将任何自定义指标设置为停止指标。自定义指标的行为应为“越少越好”,意味着自定义指标值越低,模型性能越好。自定义指标的假设下限值为 0。 -
custom_increasing
:此参数用于具有“越多越好”行为的自定义性能指标,意味着这些指标值越高,模型性能越好。在撰写本文时,此参数仅在 GBM 和 DRF 的 Python 客户端中受支持。
-
-
stopping_tolerance
:此参数表示模型性能指标必须改善的容忍值,以便停止模型训练。如果设置了stopping_rounds
并且大于0,则此参数可用。如果数据集包含至少 1 百万行,AutoML 的默认停止容忍度为0.001;否则,该值由数据集的大小和数据集中非 NA 数据量决定,导致值大于0.001。
在 H2O Flow 中,这些参数可在运行 AutoML参数的高级部分找到,如下面的截图所示:
图 8.6 – H2O Flow 中的早期停止参数
在 Python 编程语言中,您可以按以下方式设置这些参数:
aml = h2o.automl.H2OAutoML(stopping_metric = "mse", stopping_rounds = 5, stopping_tolerance = 0.001)
aml.train(x = features, y = label, training_frame = train_dataframe)
在 R 编程语言中,您可以按以下方式设置这些参数:
aml <- h2o.automl(x = features, y = label, training_frame = train_dataframe, seed = 123, stopping_metric = "mse", stopping_rounds = 5, stopping_tolerance = 0.001)
为了更好地理解 AutoML 如何提前停止模型训练,请考虑相同的 Python 和 R 示例值。我们将stopping_metric
设置为stopping_rounds
,将stopping_tolerance
设置为0.001。
在实现早期停止时,H2O 将计算最后stopping_tolerance
的0.001的移动平均值,然后 H2O 将停止模型训练。对于具有“越多越好”行为的性能指标,最佳移动平均值与参考移动平均值之比应小于或等于停止容忍度。
现在我们已经了解了如何使用stopping_rounds
、stopping_metrics
和stopping tolerance
参数来提前停止模型训练,接下来让我们了解 AutoML 中的下一个可选参数——那就是交叉验证。
尝试支持交叉验证的参数
在对数据集进行模型训练时,我们通常会对数据集进行训练-测试划分。假设我们按照 70%和 30%的比例进行划分,其中 70%用于创建训练数据集,剩下的 30%用于创建测试数据集。然后,我们将训练数据集传递给机器学习系统进行训练,并使用测试数据集来计算模型的性能。训练-测试划分通常在随机状态下进行,这意味着用于创建训练数据集的 70%的数据通常是从原始数据集中随机选择,且不进行替换,除非是时间序列数据,其中事件的顺序需要保持,或者在我们需要保持类别分层的情况下。同样,对于测试数据集,30%的数据也是从原始数据集中随机选择来创建测试数据集。
以下图表展示了如何从数据集中随机选择数据来创建用于各自目的的训练和测试数据集:
图 8.7 – 数据集上的训练-测试划分
现在,训练-测试划分的问题在于,当 30%的数据被保留在测试数据集之外而没有用于训练模型时,从这些数据中可以推导出的任何知识都无法用于训练模型,这会导致模型性能的损失。如果你使用不同的随机状态重新训练模型进行训练-测试划分,那么模型最终将具有不同的性能水平,因为它是在不同的数据记录上训练的。因此,模型的性能取决于训练数据集的随机分配。那么,我们如何既为训练提供测试数据,又保留一些测试数据进行性能测量呢?这就是交叉验证发挥作用的地方。
理解交叉验证
交叉验证是一种模型验证技术,它通过重新采样数据来训练和测试模型。该技术在每个迭代中使用数据集的不同部分进行训练和测试。通过使用数据集的不同部分进行多次模型训练和测试,然后将性能结果合并,以给出模型性能的平均估计。
让我们通过一个例子来尝试理解这个概念。假设你的数据集包含大约 1,000 条记录。为了进行交叉验证,你必须将数据集分成一个比例——假设是 1:9 的比例,其中测试数据集有 100 条记录,训练数据集有 900 条记录。然后,你在训练数据集上执行模型训练。一旦模型训练完成,你必须测试模型在测试数据集上的性能,并记录其性能。这是你的第一次交叉验证迭代。
在下一次迭代中,你以相同的 1/9 记录比例分割数据集,用于测试和训练数据集,但这次,你选择不同的数据记录来形成你的测试数据集,并使用剩余的记录作为训练数据集。然后,你在训练数据集上执行模型训练,并计算模型在测试数据集上的性能。你将使用不同的数据记录重复相同的实验,直到所有数据集都被用于训练和测试。你需要进行大约 10 次交叉验证,这样在整个交叉验证过程中,模型在每个迭代中都会在全部数据集上训练和测试,同时测试数据框中包含不同的数据记录。
一旦所有迭代完成,你必须合并实验的性能结果,并提供模型性能的平均估计。这种技术称为交叉验证。
你可能已经注意到,在交叉验证过程中,我们在同一个数据集上多次执行模型训练。这预计会增加整体机器学习过程的时间。这在执行具有非常高的训练和测试分区比的大数据集的交叉验证时尤其如此。例如,如果我们有一个包含 30,000 行的数据集,我们将数据集分成 29,000 行用于训练和 1,000 行用于测试,那么这将导致总共 3,000 次模型训练和测试的迭代。因此,有一种交叉验证的替代形式,允许你选择要执行多少次迭代:称为K 折交叉验证。
在 K 折交叉验证中,你决定 K 的值,该值用于确定要执行多少次交叉验证迭代。根据 K 的值,机器学习服务将随机将数据集分成 K 个相等的子集,这些子集将在交叉验证迭代中重采样。以下图表将帮助您理解这一点:
图 8.8 – K 折交叉验证,其中 K=3
如您所见,我们有一个包含 30,000 条数据记录的数据集,K 折交叉验证中选择的 K 值为 3。因此,数据集将被分成 20,000 条记录用于测试数据集和 10,000 条记录用于训练,这些记录将在接下来的迭代中进行重采样,从而总共进行三次交叉验证。
使用 K 折交叉验证进行模型验证的好处是模型在完整数据集上训练,而不会在训练过程中丢失数据。这在多类分类问题中尤其有益,因为模型可能会错过某些预测类别的训练,因为它被从训练数据集中分割出来用于测试数据集。
现在我们已经更好地理解了交叉验证的基本原理及其工作方式,让我们看看如何使用 H2O AutoML 训练函数中的特殊参数来执行它。
在 H2O AutoML 中处理交叉验证参数
H2O AutoML 为您提供了在支持它的所有 ML 算法上实现 K 折交叉验证的选项,以及一些可能有助于支持实现的其他信息。
您可以使用以下参数来实现交叉验证:
nfolds
: 此参数设置用于 K 折交叉验证的折叠数。
在 H2O Flow 中,此参数将在运行 AutoML参数的高级部分中可用,如下面的截图所示:
图 8.9 – H2O Flow 中的 nfolds 参数
-
fold_assignment
: 此参数用于指定用于执行 K 折交叉验证的折叠分配方案。您可以设置的折叠分配类型如下:-
AUTO
: 这个赋值允许模型训练算法选择要使用的折叠分配。AUTO
当前使用Random
作为折叠分配。 -
Random
: 这个赋值用于根据nfolds
值随机分割数据集。如果nfolds > 0
且未指定fold_column
,则默认设置此值。 -
Modulo
: 这个赋值用于在根据nfolds
值分割折叠时执行模运算。 -
Stratified
: 这个赋值用于根据分类问题的响应变量来安排折叠。
-
在 Python 编程语言中,您可以如下设置这些参数:
aml = h2o.automl.H2OAutoML(nfolds = 10, fold_assignment = "AUTO", seed = 123)
aml.train(x = features, y = label, training_frame = train_dataframe)
在 R 编程语言中,您可以如下设置这些参数:
aml <- h2o.automl(x = features, y = label, training_frame = train_dataframe, seed = 123, nfolds = 10, fold_assignment = "AUTO")
fold_column
: 此参数用于根据列的内容而不是任何程序性分配技术来指定折叠分配。您可以通过创建一个包含折叠 ID 的单独列并设置fold_column
为自定义列的名称来为数据集中的每一行自定义设置折叠值。
在 H2O Flow 中,此参数将在运行 AutoML参数的高级部分中可用,如下面的截图所示:
图 8.10 – H2O Flow 中的 fold_column 参数
在 Python 编程语言中,您可以如下设置这些参数:
aml.train(x = features, y = label, training_frame = train_dataframe, fold_column = "fold_column_name")
在 R 编程语言中,您可以如下设置这些参数:
aml <- h2o.automl(x = features, y = label, training_frame = train_dataframe, seed = 123, fold_column="fold_numbers")
-
keep_cross_validation_predictions
:在进行 K 折交叉验证时,H2O 将训练K+1个模型,其中K个模型作为交叉验证的一部分进行训练,另外1个模型在全部数据集上训练。每个交叉验证模型都会对那个迭代的测试 DataFrame 进行预测,预测值存储在预测框架中。您可以通过将此参数设置为True来保存这些预测框架。默认情况下,此参数设置为False。 -
keep_cross_validation_models
:类似于keep_cross_validation_predictions
,您也可以选择通过将此参数设置为True来保留交叉验证期间训练的模型,以便进行进一步的检查和实验。默认情况下,此参数设置为False。 -
keep_cross_validation_fold_assignment
:在交叉验证期间,数据是通过fold_cloumn
或fold_assignment
参数进行分割的。您可以通过将此参数设置为True来保存交叉验证中使用的分割分配。默认情况下,此参数设置为False。
在 H2O Flow 中,这些参数将在运行 AutoML参数的专家部分中可用,如下面的截图所示。
图 8.11 – H2O Flow 中的高级交叉验证参数
在 Python 编程语言中,您可以如下设置这些参数:
aml = h2o.automl.H2OAutoML(nfolds = 10, keep_cross_validation_fold_assignment = True, keep_cross_validation_models = True, keep_cross_validation_predictions= True, seed = 123)
aml.train(x = features, y = label, training_frame = train_dataframe)
在 R 编程语言中,您可以如下设置这些参数:
aml <- h2o.automl(x = features, y = label, training_frame = train_dataframe, seed = 123, nfolds = 10, keep_cross_validation_fold_assignment = TRUE, keep_cross_validation_models = TRUE, keep_cross_validation_predictions= TRUE)
恭喜您 – 您现在已经理解了更多高级机器学习概念以及如何在 H2O AutoML 中使用它们!
摘要
在本章中,我们学习了 H2O AutoML 中可用的某些可选参数。我们首先理解了数据集中不平衡类别的含义以及它们在训练模型时可能引起的问题。然后,我们了解了过采样和欠采样,我们可以使用这些方法来解决这个问题。之后,我们学习了 H2O AutoML 如何为我们提供参数,以便我们控制采样技术,从而处理数据集中的不平衡类别。
之后,我们了解了一个名为早期停止的概念。我们明白了过拟合如何导致机器学习模型在未见过的新的数据上表现非常糟糕。我们还了解到,早期停止是一种方法,一旦我们开始注意到模型开始过拟合,通过监控模型在验证数据集上的性能,我们可以使用这种方法来停止模型训练。然后,我们学习了 H2O AutoML 提供的各种参数,这些参数可以在模型训练过程中一旦发生过拟合时自动停止模型训练。
接着,我们了解了交叉验证是什么,以及它是如何帮助我们在整个数据集上训练模型,并像模型第一次看到数据一样验证模型性能的。我们还学习了 K 折交叉验证是如何帮助我们控制模型训练期间要执行的交叉验证迭代次数的。然后,我们探讨了 H2O AutoML 在 AutoML 训练期间执行交叉验证的各种规定。最后,我们学习了如果我们想对它们进行更多实验,我们如何保留交叉验证模型和预测,以及我们如何存储交叉验证的折分配。
在下一章中,我们将探讨 H2O AutoML 的一些杂项功能,这些功能在某些场景下对我们可能很有用。
第九章:探索 H2O AutoML 中的杂项特性
除了整合许多机器学习(ML)算法和多种特性来训练它们之外,H2O AutoML 还有一些杂项特性,使其成为一个全能型服务,能够满足各种商业需求。
H2O AutoML 的优势不仅在于其自动训练多个模型的能力,还在于提供对其他对生产级系统至关重要的服务和特性的支持。
在本章中,我们将探讨 H2O AutoML 的两个独特特性,这些特性值得了解,并且在需要时可能非常有用。第一个特性是 H2O AutoML 与 Python 中流行的机器学习库 scikit-learn 的兼容性。我们将探讨如何在 scikit-learn 实现中使用 H2O AutoML,以及它如何为庞大的 scikit-learn 社区提供价值。
第二个特性是 H2O AutoML 内置的日志系统。这个日志系统在 AutoML 训练过程中记录有价值的信息。如果您计划在生产中使用 H2O AutoML 服务,这可能特别有用,因为在生产中监控系统健康是最重要的。
在本章中,我们将涵盖以下主题:
-
理解 H2O AutoML 在 scikit-learn 中的集成
-
理解 H2O AutoML 事件日志
基于这个想法,让我们探索 H2O AutoML 与 scikit-learn 的第一个杂项特性兼容性。
技术要求
对于本章,您需要以下内容:
-
您首选的网页浏览器的最新版本
-
您选择的集成开发环境(IDE)
-
(可选)Project Jupyter 的 Jupyter Notebook (
jupyter.org/
)
本章中进行的所有实验都是在 Jupyter 笔记本上进行的,以便为您提供更好的输出可视化示例。您可以使用相同的设置自由跟随。您也可以在任何 Python 环境中执行相同的实验,因为 Python 代码在这两种环境中都会执行相同的操作。
本章的所有代码示例都可以在 GitHub 上找到,链接为 github.com/PacktPublishing/Practical-Automated-Machine-Learning-on-H2O/tree/main/Chapter%209
。
理解 H2O AutoML 在 scikit-learn 中的集成
Scikit-learn 是机器学习和数据科学领域中应用最广泛的开源机器学习库之一。它是一个用于 Python 编程语言的库,专注于机器学习工具函数。它包括执行数学和统计分析、通用机器学习算法以及用于训练、测试和评估机器学习模型的函数。
Scikit-learn 最初由 David Cournapeau 开发,最初被称为scikits.learn。它是在 2007 年作为一个 Google Summer of Code 项目创建的,同年 Matthieu Brucher 将其作为论文项目。后来,它由法国罗克恩库尔计算机科学和自动化研究所的 Fabian Pedregosa、Gael Varoquaux、Alexandre Gramfort 和 Vincent Michel 重新编写并进一步开发。Scikit-learn 的第一个版本 1 的公开发布是在 2010 年 2 月 1 日。
你可以在这里找到更多关于 scikit-learn 的详细信息:scikit-learn.org/stable/
.
scikit-learn 库建立在以下包之上:
-
NumPy:NumPy 是一个用于专门处理数组的 Python 库。它在 Python 中进行科学计算,并提供用于处理多维数组的函数。它还提供了对数组的各种快速计算数学运算,使其非常适合数据分析。它可以执行数组形状操作、排序、搜索、离散傅里叶变换操作、线性代数和统计。你可以在
numpy.org/
找到更多关于 NumPy 的详细信息。 -
SciPy:SciPy 是一个建立在 NumPy 之上的科学计算库。它提供了高级科学计算函数。它用于执行图像处理、聚类、梯度优化等操作。Python 中的所有数值计算都由 SciPy 执行。你可以在
scipy.org/
找到更多关于 SciPy 的详细信息。 -
Matplotlib:Matplotlib 是一个用于从数据创建可视化的库。这些可视化涉及各种类型的图表和图表,这些图表依赖于可以轻松用视觉表达和解释的计算数据。它可以创建适合在科学论文中发表的图表,并创建交互式图表,所有这些都可以导出为不同类型的格式。你可以在
matplotlib.org/
找到更多关于 Matplotlib 的详细信息。
数据科学家在实验数据时经常使用 Scikit-learn。它在进行实验时提供了大量的灵活性,由于其 API 非常易于使用,因此它经常是执行通用机器学习函数的首选库。
H2O AutoML 可以轻松集成到 scikit-learn 中。你可以将 H2O AutoML 用作 scikit-learn 的Estimator,并与其他 scikit-learn 函数结合使用,以充分利用两者的优点。H2O AutoML 通过h2o.sklearn模块与 scikit-learn 交互。h2o.sklearn 模块公开了两个包装函数以执行 AutoML:
-
H2OAutoMLClassifier:此函数用于使用 H2O AutoML 训练分类模型
-
H2OAutoMLRegressor:此函数用于使用 H2O AutoML 训练回归模型
这些函数接受各种格式的输入数据,如 H2Oframes、NumPy 数组,甚至是 pandas DataFrames。它们还公开了与 scikit-learn 中使用的类似的标准训练和预测 API。这使得 scikit-learn 能够使用 H2O AutoML,以及其他 scikit-learn 组件。
H2O AutoML 估计器也保留了它们原有的功能,例如排行榜和训练信息等。用户仍然可以在 scikit-learn 中访问这些详细信息,以从 AutoML 训练中提取信息进行进一步的实验或分析。
现在我们对 scikit-learn 库及其用途有了更好的了解,让我们学习如何在 H2O AutoML 旁边使用它。我们将从了解我们可以在系统上安装 scikit-learn 的各种方法开始。
构建和安装 scikit-learn
安装 scikit-learn 非常简单。在您的系统上安装 scikit-learn 有三种不同的方法:
-
安装 scikit-learn 的最新官方版本
-
安装由您的 Python 发行版或操作系统提供的 scikit-learn 版本
-
从源代码构建和安装 scikit-learn 包
让我们逐一快速了解这些选项,以便我们可以在 H2O AutoML 旁边准备好使用 scikit-learn。
安装 scikit-learn 的最新官方版本
此过程可能因您系统上使用的 Python 包管理器类型而异:
-
使用
pip
包管理器,在您的终端中执行以下命令以安装 scikit-learn 的最新版本:pip install -U scikit-learn
-
以下命令将显示 scikit-learn 的安装位置及其版本:
python -m pip show scikit-learn
-
-
使用Anaconda或Miniconda包管理器,在您的终端中执行以下命令以安装 scikit-learn 的最新版本:
conda create -n sklearn-env -c conda-forge scikit-learn conda activate sklearn-env
以下命令将显示您系统上安装的 scikit-learn 版本:
conda list scikit-learn
您可以使用以下命令导入已安装的 scikit-learn 模块,以确保它已成功安装并显示其版本:
python -c "import sklearn; sklearn.show_versions()"
现在我们知道了如何使用pip
、Anaconda 和 Miniconda 安装 scikit-learn,让我们看看另一种使用操作系统附带打包的 Python 发行版安装它的方法。
使用您操作系统的 Python 发行版安装 scikit-learn
由于 scikit-learn 被开发者广泛使用,它通常与各种 Python 发行版或操作系统的内置包管理器一起打包。这使得用户可以直接安装可用的 scikit-learn 包,而无需从互联网上下载。
以下是一些带有预包装 scikit-learn 版本及其相应终端命令的操作系统列表:
-
python-scikit-learn
。要安装此库,请执行以下命令:sudo pacman -S python-scikit-learn
-
Debian/Ubuntu:Debian Ubuntu 发行版将 scikit-learn 包分成三个部分:
-
python3-sklearn:此包包含 scikit-learn 函数的 Python 模块
-
python3-sklearn-lib:此包包含 scikit-learn 的低级实现和绑定
-
python3-sklearn-doc:此包包含 scikit-learn 的文档
-
要安装此库,请执行以下命令:
sudo apt-get install python3-sklearn python3-sklearn-lib python3-sklearn-doc
-
python3-scikit-learn
。它是Fedora30
中唯一可用的:sudo dnf install python3-scikit-learn
-
从这里:
pkgsrc.se/math/py-scikit-learn
的pkgsrc-wip
。
这个过程的缺点是它通常伴随着较旧的 scikit-learn 版本。然而,这可以通过使用相应的包管理器将已安装的包升级到最新版本来修复。
从源代码构建和安装 scikit-learn 包
想要使用最新实验功能或希望为 scikit-learn 做出贡献的用户可以直接构建和安装 scikit-learn 的最新可用版本。
您可以通过执行以下步骤从源代码构建和安装 scikit-learn:
-
使用 Git 从 GitHub 上的 scikit-learn 仓库检出最新源代码。scikit-learn 仓库可以在以下位置找到:
github.com/scikit-learn/scikit-learn
。执行以下命令以克隆最新的 scikit-learn 仓库:git clone git://github.com/scikit-learn/scikit-learn.git
-
使用 Python 创建虚拟环境并安装NumPy、SciPy和Cython,它们是 scikit-learn 的构建依赖项:
python3 -m venv h2o-sklearn source h2o-sklearn/bin/activate pip install wheel numpy scipy cython
-
使用
pip
通过运行以下命令构建项目:pip install --verbose --no-build-isolation --editable .
-
安装完成后,通过运行以下命令检查 scikit-learn 是否正确安装:
python -c "import sklearn; sklearn.show_versions()"
为了避免与其他包冲突,强烈建议在虚拟环境或conda环境中安装 scikit-learn。此外,在安装 SciPy 和 NumPy 时,建议使用二进制轮,因为它们不是从源代码重新编译的。
尝试使用 scikit-learn
现在我们已经成功安装了 scikit-learn,让我们快速看一下 scikit-learn 训练模型的一个简单实现。以此为参考,我们将探讨如何将 H2O AutoML 集成到其中。
我们将用于此实验的数据集将是我们在整本书中一直在使用的同一爱丽丝花数据集。这个数据集是使用机器学习解决分类问题的良好示例。
因此,让我们首先使用纯 scikit-learn 函数来实现它。
按照以下步骤在 Python 中使用 scikit-learn 训练您的机器学习模型:
-
导入
sklearn
和numpy
库:import sklearn import numpy
-
爱丽丝花数据集在
sklearn
库中是现成的;它在sklearn
的 dataset 子模块中。接下来,通过执行以下命令导入该数据集。让我们也仔细看看 DataFrame 的内容:from sklearn.datasets import load_iris dataframe = load_iris() print(dataframe)
你应该得到一个以字典形式显示 DataFrame 内容的输出。让我们调查字典中的重要键值对,以了解我们正在处理什么:
-
data
:此键包含数据集的所有特征——即花瓣长度、花瓣宽度、花萼长度和花萼宽度——以多维数组的形式。 -
target_names
:此键包含数据集的目标或标签的名称——即 Iris-setosa、Iris-versicolour 和 Iris-virginica。这是一个数组,名称的索引是实际数据集中使用的数值表示。 -
target
:此键包含数据集的所有目标值,也称为标签值。这也是一个表示目标值的数组,这些值在其他情况下将是表格数据集中的一列。这些值是数字,其中0
代表 Iris-setosa,1
代表 Iris-versicolour,2
代表 Iris-virginica,这是根据target_names
中的索引值决定的。
-
在这个信息的基础上,通过执行以下命令将特征和标签提取到单独的变量中:
features = dataframe.data label = dataframe.target
-
我们需要将数据集分成两部分——一部分用于训练,另一部分用于测试。与 H2O 不同,在 scikit-learn 中,我们将特征和标签视为两个独立的实体。它们应该具有相同的维度长度,以匹配数据内容。为此分割,执行以下命令:
from sklearn.model_selection import train_test_split feature_train, feature_test, label_train, label_test = train_test_split(features, label, test_size=0.30, random_state=5)
分割功能将特征和标签分割成 70%到 30%的比例,其中 70%的数据用于训练,剩余的 30%用于测试。因此,我们最终得到四个 DataFrame,如下所示:
-
feature_train
:此 DataFrame 包含用于训练的 70%的特征数据 -
label_train
:此 DataFrame 包含用于训练的 70%的标签数据 -
feature_test
:此 DataFrame 包含用于测试的 30%的特征数据 -
label_test
:此 DataFrame 包含用于测试的 30%的标签数据
-
一旦训练和测试 DataFrame 准备就绪,声明并初始化用于模型训练的 ML 算法。Scikit-learn 有针对不同类型算法的独立库。由于我们正在处理分类问题,让我们使用逻辑回归算法来训练一个分类模型。执行以下命令初始化一个逻辑回归函数以训练模型:
from sklearn.linear_model import LogisticRegression logReg = LogisticRegression(solver='lbfgs', max_iter=1000)
-
现在,让我们使用
feature_train
和label_train
数据集来训练一个模型。执行以下函数:logReg.fit(feature_train, label_train)
-
一旦训练完成,我们可以使用相同的逻辑回归对象对
feature_test
DataFrame 进行预测。执行以下命令并打印预测的输出:predictions = logReg.predict(feature_test) print(predictions)
你应该得到一个类似于以下输出的结果:
图 9.1 – scikit-learn 逻辑回归的预测输出
-
你也可以通过执行以下命令来衡量你预测的准确率:
score = logReg.score(feature_test, label_test) print(score)
你应该得到大约97.77
的准确率。
在本实验中,我们学习了如何使用 scikit-learn 导入数据集,进行分割,然后使用逻辑回归来训练分类模型。但正如我们在前几章所学,有大量的 ML 算法可供选择。每个都有自己的处理方差和偏差的方式。因此,最明显的问题仍然是未解答的:我们应该使用哪种 ML 算法?
正如我们在本实验中所看到的,scikit-learn 可能对不同的算法有大量的支持,但从编程的角度来看,训练所有这些算法可能会变得复杂。这就是我们可以集成 H2O AutoML 来自动训练所有 ML 算法的地方。
现在我们已经对如何使用 scikit-learn 来训练模型有了很好的了解,让我们看看如何使用 H2O AutoML 与 scikit-learn 结合使用。
在 scikit-learn 中使用 H2O AutoML
首先,我们将学习如何在 scikit-learn 中使用 H2O AutoML 通过H2OAutoMLClassifier
子模块来进行分类。我们将使用相同的分类 ML 问题,使用 Iris 数据集,并看看我们如何使用 H2O AutoML 训练多个模型。
实验:使用 H2OAutoMLClassifier
按照以下步骤在 Python 中使用 scikit-learn 训练你的 H2O AutoML 分类模型:
-
实施我们在“使用 scikit-learn 进行实验”部分遵循的步骤 1到4。
-
在我们在“使用 scikit-learn 进行实验”部分进行的实验中,在步骤 4之后,我们通过从
sklearn.linear_model
导入LogisticRegression
子模块初始化了逻辑回归算法。在本实验中,我们将从h2o.sklearn
模块导入H2OAutoMLClassifier
子模块:from h2o.sklearn import H2OAutoMLClassifier h2o_aml_classifier = H2OAutoMLClassifier(max_models=10, seed=5, max_runtime_secs_per_model=30, sort_metric='logloss')
就像我们在前几章中设置 AutoML 参数一样,我们将max_models
设置为10
,max_runtime_secs_per_model
设置为30
秒,随机seed
值设置为5
,以及sort_metric
设置为logloss
。
-
一旦初始化了
H2OAutoMLClassifier
,你就可以使用它来拟合,换句话说,训练你的模型。执行以下命令以触发 AutoML 训练:h2o_aml_classifier.fit(feature_train, label_train)
首先,程序将检查本地主机:54321 上是否已经运行了一个 H2O 实例。如果没有,H2O 将启动一个 H2O 服务器的实例;否则,它将重用已经存在的实例来训练 AutoML 模型。一旦开始训练,你应该得到以下类似的输出:
图 9.2 – H2O AutoML 分类器训练输出
从输出中,你可以看到 H2O 首先导入并解析了特征训练和标签训练DataFrame。然后,它开始 AutoML 训练。
-
要查看 AutoML 训练的结果,你可以通过执行以下命令来查看 H2O 排行榜:
h2o_aml_classifier.estimator.leaderboard
你应该得到以下类似的输出:
图 9.3 – H2O AutoML 排行榜
-
使用相同的 H2O AutoML 分类器,你也可以进行预测,如下所示:
predictions = h2o_aml_classifier.predict(feature_test) print(predictions)
你应该得到以下类似的输出:
图 9.4 – 使用 H2OAutoMLClassifier 进行预测的输出
默认情况下,分类器将使用排行榜上排名最高的模型进行预测。
通过这样,你已经学会了如何在 scikit-learn 中实现 H2O AutoML 来使用 H2OAutoMLClassifier
解决分类问题。
既然我们已经了解了如何使用 H2OAutoMLClassifier
对数据进行分类预测,那么让我们看看如何使用 H2OAutoMLRegressor
子模块进行回归预测。
尝试使用 H2OAutoMLRegressor
现在,让我们看看如何解决一个 H2OAutoMLRegressor
。对于这个实验,我们将使用之前在 第七章 中使用的红酒质量数据集,使用模型可解释性。
按照以下步骤在 Python 中使用 scikit-learn 训练你的 H2O AutoML 回归模型:
-
实现 步骤 1 到 4,我们在 尝试使用 scikit-learn 部分中遵循的步骤。
-
在我们进行的 尝试使用 H2OAutoMLClassifier 部分的实验中,我们初始化了
H2OAutoMLClassifier
。由于在这个实验中我们处理的是一个回归问题,我们将使用H2OAutoMLRegressor
子模块。执行以下命令来导入并实例化H2OAutoMLRegressor
类对象:from h2o.sklearn import H2OAutoMLRegressor h2o_aml_regressor = H2OAutoMLRegressor(max_models=10, max_runtime_secs_per_model=30, seed=5)
-
一旦
H2OAutoMLRegressor
已经初始化,我们可以触发 AutoML 来训练我们的回归模型。执行以下命令来触发 AutoML:h2o_aml_regressor.fit(feature_train, label_train)
一旦模型训练完成,你应该得到以下类似的输出:
图 9.5 – H2O AutoML 回归器训练输出
-
与
H2OAutoMLClassifier
类似,你也可以通过执行以下命令来查看 H2O 排行榜 上 AutoML 训练的结果:h2o_aml_regressor.estimator.leaderboard
-
进行预测也非常简单。你使用相同的
H2OAutoMLRegressor
对象,并调用其predict
方法,同时传递保留用于测试的特征数据集。执行以下命令使用由H2OAutoMLRegressor
训练的领导模型进行预测:predictions = h2o_aml_regressor.predict(feature_test) print(predictions)
你应该得到以下预测结果:
图 9.6 – 使用 H2OAutoMLRegressor 进行预测的输出
预测输出是一个包含 feature_test
DataFrame 的数组。这就是你如何在 scikit-learn 中实现 H2O AutoML 来使用 H2OAutoMLRegressor
解决回归问题的方法。
现在你已经知道了如何在 scikit-learn 中使用 H2O AutoML,让我们继续到 H2O AutoML 的下一个杂项功能:事件日志。
理解 H2O AutoML 事件日志
由于 H2O AutoML 自动化了大多数机器学习过程,我们给了机器一些控制权。封装意味着 AutoML 中所有复杂的部分都被隐藏起来,我们只关注输入和 H2O AutoML 给出的任何输出。如果 H2O AutoML 有任何问题,并且给出了没有意义或不符合预期的模型,那么我们需要深入了解 AutoML 是如何训练这些模型的。因此,我们需要一种方法来跟踪 H2O AutoML 内部发生的事情,以及它是否按预期训练模型。
当构建旨在用于生产的软件系统时,您总是会需要一个日志系统来记录信息。软件的虚拟性质使得用户难以跟踪系统在处理和其他活动中的情况。任何故障或问题都可能导致一系列底层问题,开发者可能最终发现得太晚,如果他们能发现的话。
正因如此,日志系统总是被实施以支持您的系统。系统生成的日志帮助开发者追踪问题的根源并迅速缓解。H2O AutoML 还可以生成包含所有底层处理元信息的日志。当您让 H2O 处理所有机器学习过程时,您可以使用这些日志保持一定的控制感。
AutoML 生成两种类型的日志。具体如下:
-
事件日志:这些是在 AutoML 训练过程中在后台生成的日志。所有日志都被收集并以 H2O DataFrame 的形式呈现。
-
训练日志:这些是在 AutoML 训练模型时显示训练和预测时间的日志,以键值对字典的形式呈现。训练时间以 epoch 为单位,主要用于模型训练后的分析。
让我们看看如何通过实际实现从 H2O AutoML 中检索这些日志。
按照以下步骤使用 H2O AutoML 训练模型。然后,我们将学习如何提取日志并了解它们的结构:
-
导入
h2o
模块并初始化 H2O 以启动本地 H2O 服务器:import h2o h2o.init()
-
通过传递数据集下载位置来导入 Iris 数据集:
data = h2o.import_file("Dataset/iris.data")
-
设置标签和特征:
label = "C5" features = data.columns features.remove(label)
-
使用以下参数初始化 H2O AutoML 对象:
aml = h2o.automl.H2OAutoML(max_models=10, seed = 5)
-
通过传递特征列、标签列和用于训练模型的 DataFrame 来触发 AutoML 训练:
aml.train(x = features, y = label, training_frame = dataframe)
-
一旦训练完成,您可以通过使用 AutoML 对象的
event_log
属性来查看事件日志。让我们检索日志 DataFrame 并查看其内容:event_logs = aml.event_log print(event_logs)
您应该得到类似以下输出的结果:
图 9.7 – H2O AutoML 的事件日志输出
同样,您可以通过执行以下 R 命令在 R 编程语言中查看事件日志:
event_log <- aml@event_log
事件日志包含以下信息:
-
时间戳:此列是特定事件发生的时间。
-
级别:在日志系统中,日志通常根据重要性或关键性分为某些类别。在大多数情况下,级别如下,基于关键性排名:
-
致命错误:此日志级别表示应用程序面临一个关键问题,需要停止运行并关闭。
-
错误:此日志级别表示应用程序在执行某些功能时遇到问题。然而,问题并不那么关键,以至于应用程序需要关闭。
-
警告:此日志级别表示应用程序检测到一些不寻常的情况,但无害,并且不会影响任何功能。
-
信息:此日志级别表示正常行为更新,如果需要,可以记录并存储以供将来参考。它们通常是信息性的。
-
调试:此日志级别表示在开发应用程序或进行诊断操作或调试问题时通常需要的更详细诊断信息。
-
跟踪:此日志级别类似于调试,但具有更详细的信息,尤其是在您正在跟踪代码库中信息流时。
-
-
阶段:此列指示生成日志时的 AutoML 训练阶段。
-
消息:此列包含描述性消息,提供有关发生事件的详细信息。
-
名称:如果设置了,此列包含发生的事件日志的名称。
-
值:如果设置了,此列包含发生的事件日志的值。
-
现在,让我们检索训练日志并查看其内容:
info_logs = aml.training_info print(info_logs)
您应该得到以下类似的输出:
图 9.8 – H2O AutoML 的事件日志输出
同样,您可以通过执行以下 R 命令在 R 编程语言中查看事件日志:
info_logs <- aml@training_info
训练日志包含以下信息:
-
creation_epoch
: 训练日志字典中的此键包含 AutoML 作业创建时的 epoch 值。 -
start_epoch
: 训练日志字典中的此键包含 AutoML 构建开始时的 epoch 值。 -
start_{模型名称}
: 训练日志字典中的此类键包含特定模型开始训练时的 epoch 值。 -
stop_epoch
: 训练日志字典中的此键包含 AutoML 构建停止时的 epoch 值。 -
duration_secs
: 训练日志字典中的此键包含 AutoML 运行的总时间(以秒为单位)。
这个实验为我们提供了一个很好的例子,说明了 H2O 如何生成日志事件。当使用 H2O AutoML 构建机器学习系统时,你可以将这些日志纳入你的日志系统中,以便监控 H2O AutoML 的功能。这将帮助你及时识别可能出现的任何问题,并确保你的模型在生产中保持最高质量。如果在训练过程中出现任何问题,或者在你意外地将有缺陷的模型部署到生产中之前,你将会收到警报。
摘要
在本章中,我们了解了 H2O AutoML 的一些杂项功能。我们首先理解了 scikit-learn 库,并对其实现有了初步的了解。然后,我们看到了如何在 scikit-learn 实现中使用H2OAutoMLClassifier
库和H2OAutoMLRegressor
库来训练 AutoML 模型。
然后,我们探索了 H2O AutoML 的日志系统。在那之后,我们实施了一个简单的实验,其中我们触发了 AutoML 训练;一旦完成,我们就从 Python 和 R 编程语言中提取了事件日志和训练日志。然后,我们理解了这些日志的内容以及这些信息如何帮助我们监控 H2O AutoML 的功能。
在下一章中,我们将进一步关注如何在生产中使用 H2O,以及我们如何使用 H2O 的模型对象优化来实现这一点。
第十章:与普通旧 Java 对象(POJOs)一起工作
公司通常使用多种策略,以满足预期的服务标准。对于使用机器学习(ML)的服务,他们需要考虑如何快速且容易地在生产中构建、提取和部署他们的模型,而不会影响他们正在进行的业务。
因此,训练好的模型的便携性非常重要。你是如何将使用某种技术构建的训练管道创建的模型对象用于可能使用不同技术的预测管道呢?理想情况下,模型对象应该是一个自包含且易于分发的对象。
在软件工程的世界里,Java 编程语言一直被认为是使用最广泛的平台无关编程语言之一。当 Java 编译程序时,它会将其转换为平台无关的字节码,任何安装了Java 虚拟机(JVM)的机器都可以解释这些字节码。在此基础上,你有了普通旧 Java 对象(POJOs)。
POJOs 是普通对象,任何 Java 程序都可以运行,而不管任何框架。这使得 POJOs 在部署到不同类型的机器时非常便携。H2O 还提供了提取训练模型为 POJOs 的功能,这些 POJOs 可以用于生产部署。
在本章中,我们将深入探讨 POJOs 是什么,以及如何在 Python、R 和 H2O Flow 中成功训练模型后下载它们。然后,我们将学习如何将 POJO 加载到简单的 Java 程序中以进行预测。
本章我们将涵盖以下主题:
-
POJOs 简介
-
将 H2O 模型提取为 POJOs
-
使用 H2O 模型作为 POJO
到本章结束时,你应该能够使用 Python、R 或 H2O Flow 提取训练好的模型,并以 POJOs 的形式加载这些模型到你的机器学习程序中进行预测。
技术要求
对于本章,你需要以下内容:
-
您首选网络浏览器的最新版本。
-
您选择的集成开发环境(IDE)。
-
(可选)Project Jupyter 的 Jupyter Notebook (
jupyter.org/
)
本章中进行的所有实验都是在 Jupyter 笔记本上进行的,以提供更好的输出可视化示例。你可以自由地使用相同的设置来跟随,或者在你使用的特定语言环境中执行相同的实验。本章的所有代码示例都可以在 GitHub 上找到:github.com/PacktPublishing/Practical-Automated-Machine-Learning-on-H2O/tree/main/Chapter%2010
。
POJOs 简介
POJO 是由 Martin Fowler、Rebecca Parsons 和 Josh Mackenzie 在 2000 年 9 月提出的术语。它是一个普通的 Java 对象,但使其成为“平凡旧”的不是它应该做什么,而是它不应该做什么。
在以下情况下,Java 对象可以是 POJO:
-
Java 对象不扩展自任何类。
-
Java 对象不实现任何接口。
-
Java 对象不使用任何来自外部的注解。
这三个限制导致的结果是一个不依赖于任何其他库或自身之外的 Java 对象,并且足够自包含以在其自身上执行其逻辑。由于它们的可移植性,你可以轻松地将 POJO 嵌入任何 Java 环境,并且由于 Java 的平台独立性,它们可以在任何机器上运行。
H2O 可以以 POJO 的形式导出训练好的模型。然后,这些 POJO 模型可以被部署并用于对传入数据进行预测。使用 POJO 模型的唯一依赖是 h2o-genmodel.jar
文件。这是一个必要的 JAR 文件,用于编译和运行 H2O 模型 POJO。这个 JAR 文件是一个库,包含基类和 GenModel
,一个辅助类,用于支持由 Java 生成的模型,模型 POJO 从中派生。这个相同的库还负责通过使用模型 POJO 进行评分。
在生产环境中使用模型 POJO 时,您需要 h2o-genmodel.jar
文件来编译、部署和运行您的模型 POJO。POJO 是简单的 Java 代码,不绑定到任何特定的 H2O 版本。然而,仍然建议使用 h2o-genmodel.jar
的最新版本,因为它可以加载当前版本的 POJO,以及旧版本的 POJO。您可以在 docs.h2o.ai/h2o/latest-stable/h2o-genmodel/javadoc/index.xhtml
找到有关 h2o-genmodel.jar
的详细文档。
现在我们已经了解了 POJO 是什么以及 H2O 模型 POJO 的工作原理,让我们通过简单的示例学习如何使用 AutoML 将训练好的 H2O 模型提取为 POJO。
将 H2O 模型提取为 POJO
使用 H2O 的 AutoML 训练的模型也可以提取为 POJO,以便将它们部署到您的生产系统中。
在以下子节中,我们将学习如何使用 Python 和 R 编程语言提取模型 POJO,以及如何使用 H2O Flow 提取模型 POJO。
在 Python 中将 H2O 模型作为 POJO 下载
让我们通过一个简单的 Python 示例来看看如何将 H2O 模型提取为 POJO。我们将使用迄今为止一直在使用的相同的 Iris 花数据集。此数据集可在 archive.ics.uci.edu/ml/datasets/iris
找到。
按照以下步骤在 Python 中使用 H2O AutoML 训练模型。完成此操作后,您将提取领先模型并将其作为 POJO 下载:
-
导入
h2o
模块并启动您的 H2O 服务器:import h2o h2o.init()
-
通过传递系统中的数据集位置导入数据集。执行以下命令:
data_frame = h2o.import_file("Dataset/iris.data")
-
通过执行以下命令设置特征和标签名称:
features = data_frame.columns label = "C5" features.remove(label)
-
通过执行以下命令初始化 H2O AutoML 对象并将
max_model
参数设置为10
,将seed
值设置为5
:aml=h2o.automl.H2OAutoML(max_models=10, seed = 5)
-
通过传递训练数据集、特征列和标签列作为参数来触发 AutoML,如下所示:
aml.train(x = features, y = label, training_frame = data_frame)
-
一旦训练完成,H2O AutoML 应该已经训练了几个模型,并根据默认的排名性能指标在排行榜上对它们进行了排名。排行榜上排名最高的模型被称为 领导者,可以通过使用
aml.leader
命令直接访问。使用此引用,您可以通过运行以下命令下载领导者模型作为 POJO:h2o.download_pojo(aml.leader, path="~/Downloads/", jar_name="AutoMLModel")
这应该会下载一个名为 AutoMLModel
的模型 POJO,如 jar_name
参数中指定的,到 path
参数中指定的路径。如果未设置 path
参数,则 H2O 将在控制台上打印模型 POJO 的详细信息,而不是将其作为 JAR 文件下载。
您还可以通过在任何编辑器中打开文件来查看 POJO 的内容。该文件将包含一个名为您的领导者模型并扩展 GenModel
类的公共类,该类是 h2o-genmodel.jar
的一部分。
现在我们知道了如何使用 Python 提取 POJO 模型,让我们看看 R 编程语言中的类似示例。
在 R 中下载 H2O 模型作为 POJO
与我们可以在 Python 中从 AutoML 排行榜中提取模型的方式类似,我们也可以在 R 编程语言中做到这一点。在本节中,我们将使用相同的 Iris 花朵数据集。按照以下步骤使用 H2O AutoML 训练模型,然后提取领导者模型以将其作为 POJO 下载:
-
导入
h2o
模块并启动您的 H2O 服务器:library(h2o) h2o.init()
-
通过传递系统中的数据集位置导入数据集。执行以下命令:
data_frame <- h2o.importFile("Dataset/iris.data")
-
通过执行以下命令设置特征和标签名称:
label <- "C5" features <- setdiff(names(data), label)
-
通过传递训练数据集、特征列和标签列作为参数来触发 AutoML。同时,将
max_models
设置为10
,将seed
值设置为5
:aml <- h2o.automl(x = features, y = label, training_frame = data_frame, max_models=10, seed = 5)
-
一旦训练完成并且您有了排行榜,您可以使用
aml@leaderboard
访问领导者模型。我们还可以通过执行以下命令下载领导者模型作为 POJO:h2o.download_pojo(aml@leaderboard, path="~/Downloads/", jar_name="AutoMLModel")
这将开始将 AutoMLModel
模型 POJO 下载到您指定的路径上的设备。
现在我们知道了如何在 R 编程语言中提取 POJO 模型,让我们看看如何在 H2O Flow 中做到这一点。
在 H2O Flow 中下载 H2O 模型作为 POJO
在 H2O Flow 中下载模型 POJO 非常简单。H2O 允许通过简单地点击按钮将模型下载为 POJO。在 第二章 的 使用 H2O Flow (H2O 的 Web UI) 部分的 在 H2O Flow 中使用模型训练函数 部分,您学习了如何访问特定模型的信息。
在 H2O Flow 中,每个模型的输出信息在Actions子部分中,你都会看到一个名为Download POJO的交互式按钮,如下截图所示:
图 10.1 – 使用“Download POJO”按钮收集模型信息
你可以简单地点击Download POJO按钮来下载模型作为 POJO。你可以通过在 H2O Flow 中使用这个交互式按钮下载 H2O 训练的所有模型。
现在我们已经探讨了如何在 Python、R 和 H2O Flow 中下载模型为 POJO,让我们学习如何使用这个模型 POJO 进行预测。
使用 H2O 模型作为 POJO
如前所述,模型 POJO 可以在任何安装了 JVM 的平台中使用。唯一的依赖项是h2o-genmodel.jar
文件,这是一个 JAR 文件,用于编译和运行模型 POJO 以进行预测。
因此,让我们完成一个实验,我们可以使用模型 POJO 和h2o-genmodel.jar
文件来了解我们如何在任何具有 JVM 的环境中使用模型 POJO。我们将编写一个 Java 程序,导入h2o-genmodel.jar
文件,并使用它将模型 POJO 加载到程序中。一旦模型 POJO 被加载,我们将使用它对样本数据进行预测。
因此,让我们首先创建一个文件夹,我们可以在这里保存实验所需的 H2O POJO 文件,然后编写一些使用它的代码。按照以下步骤操作:
-
打开你的终端,通过执行以下命令创建一个空文件夹:
mkdir H2O_POJO cd H2O_POJO
-
现在,通过执行以下命令将你的模型 POJO 文件复制到文件夹中:
mv {path_to_download_location}/{name_of_model_POJO} .
请记住,你可能需要提及你下载的模型名称,以及你下载模型 POJO 文件的路径。
-
然后,你需要下载
h2o-genmodel.jar
文件。你有两种方法可以做到这一点:- 你可以通过运行以下命令从当前运行的本地 H2O 服务器下载
h2o-genmodel.jar
文件:
curl http://localhost:54321/3/h2o-genmodel.jar > h2o-genmodel.jar
- 你可以通过运行以下命令从当前运行的本地 H2O 服务器下载
请记住,你需要一个正在运行的 H2O 服务器,该服务器位于localhost:54321
。如果你的服务器运行在不同的端口上,请使用适当的端口号编辑命令。
h2o-genmodel.jar
文件也作为pom.xml
文件中的dependencies
标签的一部分提供,最好是最新版本:
<dependency>
<dependency>
<groupId>ai.h2o</groupId>
<artifactId>h2o-genmodel</artifactId>
<version>3.35.0.2</version>
</dependency>
这个 Maven 仓库可以在这里找到:https://mvnrepository.com/artifact/ai.h2o/h2o-genmodel。
-
现在,让我们创建一个使用模型 POJO 和
h2o-genmodel.jar
文件对随机数据值进行预测的样本 Java 程序。通过在终端中执行以下命令创建一个名为main.java
的 Java 程序:vim main.java
这应该会为你打开vim
编辑器,以便你可以在其中编写程序。
-
让我们开始编写我们的 Java 程序:
- 首先,导入必要的依赖项,如下所示:
import hex.genmodel.easy.RowData; import hex.genmodel.easy.EasyPredictModelWrapper; import hex.genmodel.easy.prediction.*;
- 然后,创建
main
类,如下所示:
public class main { }
- 在
main
类内部,声明我们的模型 POJO 的类名,如下所示:
private static final String modelPOJOClassName = "{name_of_model_POJO}";
- 然后,在
main
类内部创建一个main
函数,如下所示:
public static void main(String[] args) throws Exception { }
- 在这个
main
函数内部,将rawModel
变量声明为GenModel
对象,并通过创建一个modelPOJOClassName
实例来初始化它,如下所示:
hex.genmodel.GenModel rawModel; rawModel = (hex.genmodel.GenModel) Class.forName(modelPOJOClassName).getDeclaredConstructor().newInstance();
- 现在,让我们将这个
rawModel
对象包装在EasyPredictModelWrapper
类中。这个类带有易于使用的函数,这将使我们的预测变得容易。将以下代码添加到你的文件中:
EasyPredictModelWrapper model = new EasyPredictModelWrapper(rawModel);
- 现在我们已经加载了
modelPOJO
对象并将其包装在EasyPredictModelWrapper
中,让我们创建一些用于预测的样本数据。由于我们使用的是使用 Iris 数据集训练的模型,让我们创建一个包含C1
、C2
、C3
和C4
作为特征和一些适当值的RowData
。将以下代码添加到你的文件中:
RowData row = new RowData(); row.put("C1", 5.1); row.put("C2", 3.5); row.put("C3", 1.4); row.put("C4", 0.2);
- 现在,我们需要创建一个预测处理对象,我们可以用它来存储预测结果。由于 Iris 数据集是用于多项式分类问题,我们将创建一个适当的多元预测处理对象,如下所示:
MultinomialModelPrediction predictionResultHandler = model.predictMultinomial(row);
对于不同类型的问题,你需要使用适当的预测处理对象类型。你可以在以下链接中找到更多信息:docs.h2o.ai/h2o/latest-stable/h2o-genmodel/javadoc/index.xhtml
。
- 现在,让我们添加一些
print
语句,以便我们可以得到干净且易于理解的输出。添加以下print
语句:
System.out.println("Predicted Class of Iris flower is: " + predictionResultHandler.label);
predictionResultHandler.label
将包含预测的标签值。
- 让我们也打印出不同类别的概率,这样我们就可以了解标签预测的概率是多少:
System.out.println("Class probabilities are: ");
for (int labelClassIndex = 0; labelClassIndex < predictionResultHandler.classProbabilities.length; labelClassIndex++) {
System.out.println(predictionResultHandler.classProbabilities[labelClassIndex]);
}
-
最后,作为最重要的步骤,确保所有的大括号都正确关闭并保存文件。
-
一旦你的文件准备就绪,只需执行以下命令来编译文件:
javac -cp h2o-genmodel.jar -J-Xmx2g -J-XX:MaxPermSize=128m DRF_1_AutoML_1_20220619_210236.java main.java
-
一旦编译成功,通过在终端运行以下命令来执行编译后的文件:
java -cp .:h2o-genmodel.jar main
你应该得到以下输出:
图 10.2 – H2O 模型 POJO 实现中的预测结果
如您所见,使用模型 POJO 非常简单——你只需要创建 POJO 并在任何常规 Java 程序中使用它,通过实现h2o-genmodel.jar
文件。
小贴士
如果你计划在生产中使用模型 POJO,那么深入了解h2o-genmodel.jar
库是非常推荐的。这个库可以为你提供许多功能和特性,让你的部署体验变得简单。你可以在以下链接中了解更多关于这个库的信息:docs.h2o.ai/h2o/latest-stable/h2o-genmodel/javadoc/index.xhtml
。
恭喜!这一章已经帮助你理解了如何构建、提取和部署模型 POJO 以对传入数据进行预测。你现在离在生产中使用 H2O 又近了一步。
摘要
在本章中,我们首先了解了在生产中使用 ML 服务时通常会遇到的问题。我们理解了软件以及 ML 模型的可移植性在无缝部署中扮演着重要角色。我们还理解了 Java 的平台独立性使其适合部署,以及 POJO 在其中扮演的角色。
然后,我们探讨了 POJO 是什么以及它们如何在 Java 领域中作为独立运作的对象。我们还了解到,H2O 提供了提取由 AutoML 训练的模型的功能,这些模型以 POJO 的形式存在,我们可以将其用作自包含的 ML 模型,能够进行预测。
在此基础上,我们学习了如何在 H2O 中以 Python、R 和 H2O Flow 的形式提取 ML 模型作为 POJO。一旦我们了解了如何下载 H2O ML 模型作为 POJO,我们就学习了如何使用它们进行预测。
首先,我们了解到我们需要h2o-genmodel.jar
库,并且它负责在 Java 中解释模型 POJO。然后,我们创建了一个实验,其中我们下载了 H2O 模型 POJO 和h2o-genmodel.jar
,并创建了一个简单的 Java 程序,该程序使用这两个文件对一些样本数据进行预测;这让我们在处理模型 POJO 方面获得了一些实践经验。
在下一章中,我们将探讨 MOJO,这些对象类似于 POJO,但具有一些特殊的好处,也可以在生产中使用。
第十一章:与模型对象,优化(MOJO)一起工作
如我们在第十章中学习的,与普通 Java 对象(POJOs)一起工作,当与生产系统一起工作时,我们需要易于部署到我们生产服务器的可移植软件。在机器学习(ML)服务中,ML 模型的可移植性和自给自足性尤为重要。这有助于工程师定期部署新模型,而无需担心由于任何依赖性问题而破坏他们的生产系统。
H2O 的模型 POJOs 是解决这个问题的良好方案。模型 POJOs 是 H2O 模型,可以以 Java POJOs 的形式提取,您可以直接使用h2o-genmodel.jar
运行它们。
然而,模型 POJOs 存在一些缺点,这阻碍了它们成为解决所有这些问题的最佳方案。当涉及到包括 POJOs 在内的软件包的可移植性时,对象越小,部署它就越快。POJOs 在源文件大小上有一个固有的限制,最大为 1 GB。因此,大于 1 GB 的大型模型不能被提取为 POJOs,同时,大型模型的部署和性能可能会较慢。
正因如此,H2O.ai 团队创建了一个名为模型对象,优化(MOJO)的 POJOs 的替代方案。MOJOs 是低延迟、自给自足且独立的对象,可以轻松部署到生产环境中。它们是比 POJOs 更小、更快的替代品,并且与 POJOs 一样易于提取和使用。
在本章中,我们将涵盖以下主题:
-
理解什么是 MOJO
-
将 H2O 模型提取为 MOJOs
-
查看模型 MOJOs
-
使用 H2O AutoML 模型 MOJOs 进行预测
到本章结束时,您将能够理解 POJOs 和 MOJOs 之间的区别,使用 Python、R 或 H2O Flow 以 MOJOs 的形式提取训练模型,然后使用这些 MOJO 模型将您的 ML 程序加载以进行预测。
技术要求
在本章中,您需要以下内容:
-
您首选网络浏览器的最新版本
-
您选择的集成开发环境(IDE)
-
(可选)Project Jupyter 的 Jupyter Notebook (
jupyter.org/
)
本章中进行的所有实验都是在终端上进行的。您可以选择使用相同的设置来跟进,或者使用您选择的任何 IDE 执行相同的实验。本章的所有代码示例都可以在 GitHub 上找到:github.com/PacktPublishing/Practical-Automated-Machine-Learning-on-H2O/tree/main/Chapter%2011
。
理解什么是 MOJO
MOJOs是 H2O 模型 POJOs 的对立面,在技术上以相同的方式工作。H2O 可以构建和提取以 MOJOs 形式训练的模型,您可以使用提取的 MOJOs 来部署并对传入数据进行预测。
那么,是什么让 MOJOs 与 POJOs 不同?
POJOs 存在某些缺点,使得它们在生产环境中使用略逊于理想,如下所示:
-
对于大于 1 GB 的源文件,不支持 POJOs,因此任何大于 1 GB 的模型都不能编译为 POJOs。
-
POJOs 不支持堆叠集成模型或 Word2Vec 模型。
另一方面,MOJOs 具有以下额外的好处:
-
MOJOs 没有尺寸限制
-
MOJOs 通过移除 ML 树并使用通用的树遍历算法来导航模型,从而解决了大型尺寸问题。
-
MOJOs 的尺寸比 POJOs 小,且速度更快
-
MOJOs 支持使用 H2O AutoML 训练的所有类型的模型
根据 H2O 的内部实验和测试,如 https://docs.h2o.ai/h2o/latest-stable/h2o-docs/productionizing.xhtml#benefits-of-mojos-over-pojos 中所述,注意到 MOJO 模型在磁盘空间上大约比相应的 POJO 模型小 20-25 倍。在热评分时,即 JVM 能够优化执行路径之后进行评分时,MOJOs 比 POJOs 快两倍。在冷评分时,即 JVM 优化执行路径之前进行评分时,MOJOs 比 POJOs 快约 10-40 倍。随着模型尺寸的增加,MOJOs 比 POJOs 更高效。
H2O 的内部测试也显示,当使用 5,000 个深度为 25 的树进行测试时,在运行深度约为 50 且深度为 5 的小树上的二项式分类时,POJOs 的表现更好,但 MOJOs 在多项式分类中表现更佳。
现在我们已经了解了 MOJOs 以及它们的优点,让我们看看如何使用简单的示例提取使用 H2O 的 AutoML 训练的模型作为 MOJOs。
将 H2O 模型提取为 MOJOs
就像 POJOs 一样,您可以使用任何 H2O 支持的语言提取使用 H2O 的 AutoML 训练的模型。
在以下子节中,我们将学习如何使用 Python 和 R 编程语言提取模型 MOJOs,以及如何使用 H2O Flow 提取模型 MOJOs。
在 Python 中将 H2O 模型提取为 MOJOs
让我们看看如何使用 Python 提取模型为 MOJOs。我们将使用相同的鸢尾花数据集来运行 AutoML。
按照以下步骤使用 H2O AutoML 训练模型。然后,我们将提取领先模型并将其作为 MOJO 下载:
-
导入
h2o
模块并启动 H2O 服务器:import h2o h2o.init()
-
通过在系统中传递数据集的适当位置导入 Iris 数据集。执行以下命令:
data_frame = h2o.import_file("Dataset/iris.data")
-
通过执行以下命令设置特征和标签名称:
features = data_frame.columns label = "C5" features.remove(label)
-
通过执行以下命令,通过将
max_model
参数的值设置为10
和将seed
值设置为5
来初始化 H2O AutoML 对象:aml=h2o.automl.H2OAutoML(max_models=10, seed = 5)
-
通过传递训练数据集、特征列和标签列作为参数来启动 AutoML 过程,如下所示:
aml.train(x = features, y = label, training_frame = data_frame)
-
一旦训练完成,您可以通过执行以下命令来查看 AutoML 排行榜:
print(aml.leaderboard)
你应该得到以下排行榜:
图 11.1 – 提取 MOJO 的 AutoML 排行榜
-
你可以使用
aml.leader
获取 AutoML 训练的领先模型。所有模型都有一个内置函数,download_mojo()
,用于提取和下载模型 MOJO 文件:aml.leader.download_mojo()
这应该将模型 MOJO 下载到你的设备。你也可以使用 model_id
从排行榜下载特定的模型。让我们下载排名第四的 DRF 模型。执行以下命令:
DRF_model = h2o.get_model(aml.leaderboard[3,0])
DRF_model.download_mojo()
你也可以通过将 path
参数与位置一起传递给 download_mojo()
函数来指定你想要 MOJO 文件下载的路径。你还可以通过在 download_mojo()
函数中将 get_genmodel_jar
设置为 True
来下载 h2o-genmodel.jar
文件,以及 MOJO 文件。
让我们看看如何在 R 编程语言中做同样的事情。
在 R 中提取 H2O 模型作为 MOJO
类似于我们可以在 Python 中的 AutoML 排行榜中提取模型,我们也可以在 R 编程语言中做同样的事情。我们将再次使用相同的 Iris 花数据集来训练模型,使用 H2O AutoML 并提取排行榜中的领先模型以下载为 POJO。按照以下步骤操作:
-
导入
h2o
模块并启动你的 H2O 服务器:library(h2o) h2o.init()
-
通过传递数据集在系统中的位置来导入数据集。执行以下命令:
data_frame <- h2o.importFile("Dataset/iris.data")
-
通过执行以下命令设置特征和标签名称:
label <- "C5" features <- setdiff(names(data), label)
-
通过传递训练数据集、特征列和标签列作为参数来触发 AutoML。同时,将
max_models
设置为10
和seed
值设置为5
:aml <- h2o.automl(x = features, y = label, training_frame = data_frame, max_models=10, seed = 5)
-
一旦训练完成并且你有了排行榜,你可以使用
aml@leaderboard
访问排行榜模型。使用相同的命令,我们可以下载排行榜模型作为 MOJO,如下所示:h2o.download_pojo(aml@leaderboard)
这将开始将模型 MOJO ZIP 文件下载到你的设备。类似于 Python,在 R 中,你也可以指定下载路径,并将 get_genmodel_jar
参数设置为 True 以下载 h2o-genmodel.jar
文件,以及 MOJO ZIP 文件。
现在我们知道了如何在 R 编程语言中提取模型 MOJO,让我们学习如何在 H2O 流中做同样的事情。
在 H2O 流中提取 H2O 模型作为 MOJO
在 H2O 流中下载模型 MOJO 与使用 POJO 一样简单。在 下载 POJO 按钮旁边,你还有一个按钮用于下载 MOJO 模型。
如你在 第二章 中所学的,在 使用 H2O 流(H2O 的 Web UI) 部分,在 使用 H2O 流中的模型训练函数 部分,你可以访问特定模型的信息。
在 操作 子部分中,你有一个名为 模型部署包(MOJO) 的交互式按钮,如下面的截图所示:
图 11.2 – 下载模型部署包(MOJO)按钮
简单地点击此按钮即可将模型下载为 MOJO。所有模型都可以通过使用 H2O Flow 中的此交互式按钮以这种方式下载。
与 POJOs 不同,您只有一个 Java 文件,MOJOs 可以下载为ZIP 文件,其中包含一组特定的配置设置以及其他文件。如果您愿意,可以提取并探索这些文件,但从实现的角度来看,我们将使用整个 ZIP 文件,并在我们的服务中使用它。
但无论文件类型如何不同,无论是 Java 文件还是 ZIP 文件,h2o-genmodel.jar
都提供了对这两种文件类型的解释器和读取器,您可以使用它们来读取模型并做出预测。
现在我们已经提取了模型 MOJO,让我们探索 MOJO 中的一个特殊功能,我们可以通过图形化查看训练模型的内部内容。
查看模型 MOJO
您可以使用名为Graphviz的 Java 工具将 MOJO 模型视为简单的人类可读图。Graphviz 是一款用于以图表或图形的形式图形化展示结构信息的可视化软件。这是一个方便的工具,常用于以简单图像的形式展示网络、网页设计和机器学习中的技术细节。
您可以在不同的操作系统上安装 Graphviz 库,如下所示:
-
Linux:您只需在您的终端中运行以下命令即可下载库:
sudo apt install graphviz
-
使用
brew
在您的 Mac 系统中安装此库。在 Mac 终端中执行以下命令:brew install graphviz
-
Windows:Graphviz 有一个 Windows 安装程序,您可以从 http://www.graphviz.org/download/下载。
一旦您安装了 Graphviz,您可以使用终端中的PrintMojo
函数来图形化查看模型。
让我们试试。执行以下步骤:
-
一旦您下载了模型 MOJO 文件并安装了 Graphviz,您需要将
h2o.jar
文件放在同一路径下,以便在hex
类中访问printMojo()
函数。您可以从 http://h2o-release.s3.amazonaws.com/h2o/rel-zumbo/2/index.xhtml 下载h2o.jar
文件。 -
一旦您的文件准备就绪,在相同目录下打开您的终端并执行以下命令:
java -cp h2o.jar hex.genmodel.tools.PrintMojo --tree 0 -i "DRF_1_AutoML_4_20220801_225630.zip" -o model.gv -f 20 -d 3
我们正在使用我们从提取 H2O 模型作为 Python 中的 MOJO部分进行的实验中下载的 DRF 模型。此命令生成一个model.gv
文件,Graphviz 可视化工具可以使用它来可视化模型。
-
现在,使用 Graphviz 工具通过
model.gv
文件构建一个 PNG 文件。执行以下代码:dot -Tpng model.gv -o model.png
这将生成model.png
文件。
- 现在,打开
model.png
文件;您应该看到一个模型的图像。模型应该看起来如下:
图 11.3 – 使用 Graphviz 从 MOJO 生成的模型图像
上述图表是PrintMojo
函数决策树的一个很好的图形表示,无需 Graphviz 库。然而,此选项仅在 Java 8 及以上版本中可用。
-
让我们尝试使用
PrintMojo
函数生成模型图像。按照顺序执行以下步骤以生成不使用 Graphviz 的模型图像。 -
与之前使用 Graphviz 打印模型 MOJO 的实验类似,请确保您已下载模型 MOJO 并将其复制到目录中,包括您的
h2o.jar
文件。现在,在同一文件夹中打开一个终端并执行以下命令:java -cp h2o.jar hex.genmodel.tools.PrintMojo --tree 0 -i "DRF_1_AutoML_7_20220622_170835.zip" -o tree.png --format png
此命令的输出应生成一个包含决策树图像的tree.png
文件夹。图表应如下所示:
图 11.4 – 使用 PrintMojo 和 Graphviz 生成 Iris-setosa 类的图形图像
由于我们使用的是在 Iris 数据集上训练的 ML 模型,因此我们有一个多项式分类模型。因此,在tree.png
文件中,您将为每个类别有单独的图像 – 一个用于Iris-setosa
,一个用于Iris-virginica
,一个用于Iris-versicolor
。
注意,此功能仅适用于基于树的算法,如 DRF、GBM 和 XGBoost。GLM 等线性模型和深度学习模型不支持查看。
现在我们已经知道如何从模型 MOJO 中查看模型,让我们学习如何使用 MOJO 进行预测。
使用 H2O AutoML 模型 MOJO 进行预测
使用 MOJO 进行预测与使用模型 POJO 进行预测的方法相同,尽管有一些小的变化。类似于 POJOs,编译和运行模型 MOJO 进行预测依赖于h2o-genmodel.jar
文件。
因此,让我们快速运行一个实验,在这个实验中,我们可以使用h2o-genmodel.jar
文件与模型 MOJO 进行预测。我们将编写一个 Java 程序,导入h2o-genmodel.jar
文件并使用其类来加载和使用我们的模型 MOJO 进行预测。
因此,让我们首先创建一个文件夹,用于存放实验所需的 H2O MOJO 文件,然后编写一些使用它的代码。
按照以下步骤操作:
-
打开您的终端并执行以下命令创建一个空文件夹:
mkdir H2O_MOJO cd H2O_MOJO
-
现在,通过执行以下命令将您的模型 MOJO 文件复制到文件夹中:
mv ~/Downloads/DRF_1_AutoML_7_20220622_170835.zip .
确保将模型 MOJO 的名称DRF_1_AutoML_7_20220622_170835.zip
更改为您正在使用的模型 MOJO。
-
然后,您需要下载
h2o-genmodel.jar
文件。正如您在第十章中学习的,与 Plain Old Java Objects (POJOs)一起工作,您有两种方法可以这样做。您可以从当前运行的本地 H2O 服务器下载h2o-genmodel.jar
文件,或者如果您正在使用h2o-genmodel
,如下所示:<dependency> <groupId>ai.h2o</groupId> <artifactId>h2o-genmodel</artifactId> <version>3.35.0.2</version> </dependency>
这个 Maven 仓库可以在以下位置找到:https://mvnrepository.com/artifact/ai.h2o/h2o-genmodel。
-
现在,让我们创建一个 Java 程序,该程序将使用模型 MOJO 进行预测。通过在终端执行以下命令创建一个名为
main.java
的 Java 程序:vim main.java
这应该会打开vim
编辑器,你可以在其中编写代码。
-
让我们开始编写我们的 Java 程序:
- 首先,导入必要的依赖项,如下所示:
import hex.genmodel.easy.RowData; import hex.genmodel.easy.EasyPredictModelWrapper; import hex.genmodel.easy.prediction.*; import hex.genmodel.MojoModel;
- 然后,创建
main
类,如下所示:
public class main { }
- 然后,在
main
类中,创建一个main
函数,如下所示:
public static void main(String[] args) throws Exception { }
- 在这个
main
函数内部,通过使用MojoModel.load()
函数并传递你的模型 MOJO 的位置来创建EasyPredictModelWrapper
对象。相应的代码如下:
EasyPredictModelWrapper modelMOJO = new EasyPredictModelWrapper(MojoModel.load("DRF_1_AutoML_7_20220622_170835.zip"));
- 现在我们已经加载并包装了我们的模型 MOJO,让我们创建我们将用于进行预测的样本数据。将以下代码添加到你的文件中:
RowData row = new RowData(); row.put("C1", 5.1); row.put("C2", 3.5); row.put("C3", 1.4); row.put("C4", 0.2);
- 与我们使用模型 POJO 进行预测时的方式相似,我们需要一个预测处理程序来存储模型 MOJOs 的预测结果。用于 POJOs 的预测处理程序也可以与 MOJOs 一起使用。因此,让我们创建一个适当的多元预测处理程序对象,如下所示:
MultinomialModelPrediction predictionResultHandler = modelMOJO.predictMultinomial(row);
- 现在,让我们添加必要的
print
语句,以便我们有干净且易于理解输出的方式。添加以下print
语句:
System.out.println("Predicted Class of Iris flower is: " + predictionResultHandler.label);
predictionResultHandler.label
将包含预测的标签值。
- 让我们也打印出不同的类别概率。添加以下代码:
System.out.println("Class probabilities are: ");
for (int labelClassIndex = 0; labelClassIndex < predictionResultHandler.classProbabilities.length; labelClassIndex++) {
System.out.println(predictionResultHandler.classProbabilities[labelClassIndex]);
}
-
确保所有大括号都已正确关闭,并保存文件。
-
一旦你的文件准备就绪,只需通过执行以下命令来编译文件:
javac -cp h2o-genmodel.jar -J-Xmx2g -J-XX:MaxPermSize=128m main.java
-
一旦编译成功,通过在终端运行以下命令来执行编译后的文件:
java -cp .:h2o-genmodel.jar main
你应该得到以下输出:
图 11.5 – H2O 模型 MOJO 实现的预测结果
如你所见,使用模型 MOJO 和 POJO 一样简单。两者都易于提取并在生产中使用。然而,MOJOs 由于模型尺寸较大且运行更快而具有优势,这使得它们相对于 POJOs 略胜一筹。
恭喜!你现在知道如何构建、提取和部署模型 MOJOs 进行预测。
摘要
在本章中,我们首先了解了 POJOs 的缺点。然后,我们学习了 H2O 为 POJOs 创建了一个对应物,称为 MOJOs,它们没有 POJOs 所具有的问题。然后,我们学习了 MOJOs 是什么以及与 POJOs 相比使用它们的优点。我们了解到 MOJOs 比 POJOs 更小、更快。在 H2O 的内部实验中,发现 MOJOs 在处理大型机器学习模型时表现更好。
之后,我们学习了如何实际地将使用 AutoML 训练的机器学习模型提取为 MOJOs。我们了解了如何在 Python、R 和 H2O Flow 中下载 MOJOs。我们还发现 MOJOs 的一个好处是存在一个名为PrintMojo
的特殊函数,它可以用来创建人类可读的机器学习模型的图形化图片。这也使得理解机器学习模型的内容变得容易。
在这个知识的基础上,我们实施了一个实验,在该实验中,我们使用了h2o-genmodel.jar
文件以及模型 MOJO,对样本数据进行预测,从而帮助我们更好地理解如何在生产环境中使用 MOJOs。
在下一章中,我们将探讨我们可以用来实现 H2O AutoML 的各种设计模式。这将帮助我们理解如何使用 H2O AutoML 实现理想的机器学习解决方案。
第十二章:与 H2O AutoML 和 Apache Spark 协同工作
在第十章 使用普通的 Java 对象(POJOs)和第十一章 使用模型对象,优化(MOJO)中,我们探讨了如何在生产系统中构建和部署我们的机器学习(ML)模型作为 POJOs 和 MOJOs,并使用它们进行预测。在大多数现实世界的问题中,你通常会需要在生产中部署你的整个 ML 管道,这样你就可以实时部署和训练模型。你的系统也将收集和存储新的数据,你可以稍后使用这些数据重新训练你的模型。在这种情况下,你最终需要将你的 H2O 服务器集成到你的商业产品中,并协调 ML 工作。
Apache Spark 是机器学习领域更常用的技术之一。它是一个用于大规模数据处理的集群计算分析引擎。它是完全开源的,并且得到了 Apache 软件基金会的广泛支持。
考虑到 Spark 在数据处理领域的普及,H2O.ai 开发了一个优雅的软件解决方案,将 Spark 和 AutoML 的优点结合成一个一站式解决方案,用于机器学习(ML)管道。这个软件产品被称为 H2O Sparkling Water。
在本章中,我们将更深入地了解 H2O Sparkling Water。首先,我们将了解 Spark 是什么以及它是如何工作的,然后继续了解 H2O Sparkling Water 如何与 Spark 结合操作 H2O AutoML,以满足快速数据处理需求。
在本章中,我们将涵盖以下主题:
-
探索 Apache Spark
-
探索 H2O Sparkling Water
到本章结束时,你应该对如何使用 H2O Sparkling Water 将 H2O AI 与 Apache Spark 相结合有一个大致的了解,以及你如何从这两个世界的最佳之处受益。
技术要求
对于本章,你需要以下内容:
-
你首选的网页浏览器的最新版本。
-
你选择的集成开发环境(IDE)或终端。
-
本章中进行的所有实验都是在终端上进行的。你可以自由地使用相同的设置来跟随,或者使用你选择的任何 IDE 进行相同的实验。
因此,让我们首先了解 Apache Spark 究竟是什么。
探索 Apache Spark
Apache Spark 始于 2009 年在加州大学伯克利分校的 AMPLab 的一个项目。它在 2010 年以 BSD 许可证开源。三年后,即 2013 年,它被捐赠给 Apache 软件基金会,成为顶级项目。一年后,它在 Databricks 举办的数据排序比赛中被使用,并创下了新的世界纪录。从那时起,它被广泛用于大数据行业中的内存分布式数据分析。
让我们看看 Apache Spark 的各个组件及其相应的功能。
理解 Apache Spark 的组件
Apache Spark是一个开源的数据处理引擎。它用于实时处理数据,以及通过集群计算进行批量处理。所有数据处理任务都在内存中执行,使得任务执行非常快速。Apache Spark 的数据处理能力与 H2O 的 AutoML 功能相结合,可以使您的机器学习系统运行得更高效、更强大。但在我们深入探讨 H2O Sparkling Water 之前,让我们先了解 Apache Spark 是什么以及它由什么组成。
让我们先了解 Spark 生态系统中的各种组件:
图 12.1 – Apache Spark 组件
Spark 生态系统的各种组件如下:
-
Spark Core:Spark Core 组件是 Spark 生态系统中最关键的部分。它负责基本功能,如输入输出操作、作业调度和监控。所有其他组件都是基于这个组件构建的。该组件通过特定的接口支持 Scala、Java、Python 和 R 编程语言。Spark Core 组件本身是用 Scala 编程语言编写的。
-
Spark SQL:Spark SQL 组件用于利用 SQL 查询的强大功能,在 Spark 节点存储的数据上运行数据查询。
-
Spark Streaming:Spark Streaming 组件用于在同一个应用程序中批量处理以及流式处理数据。
-
Spark MLlib:Spark MLlib 是 Spark 用于开发和部署可扩展机器学习管道的 ML 库。它还用于执行机器学习分析任务,如特征提取、特征工程、降维等。
-
GraphX:GraphX 组件是一个用于在基于图的数据上执行数据分析的库。它用于执行图数据构建和遍历。
-
Spark R:Spark R 组件是一个 R 包,为用户提供了一个通过 R 编程语言与 Spark 通信的前端 shell。所有由 R 执行的数据处理都在单个节点上完成。这使得 R 不适用于处理大量数据。Spark R 组件通过使用底层的 Spark 集群,帮助用户以分布式方式在大型数据集上执行这些数据操作。
理解 Apache Spark 架构
Apache Spark 具有一个明确的架构。如前所述,Spark 在集群系统上运行。在这个集群中,您将有一个节点被指定为主节点,而其他节点则作为工作节点。所有这些工作都是由工作节点上的独立进程完成的,而整个工作的协调则由 Spark 上下文完成。
参考以下图表以更好地理解 Apache Spark 架构:
图 12.2 – Apache Spark 架构
Spark 架构包括以下组件:
- Spark 集群管理器:Spark 集群管理器负责管理资源分配给节点并监控其健康状态。它负责维护 Spark 应用程序运行的机器集群。当你启动一个 Spark 应用程序时,集群管理器将根据指定的配置启动集群中的不同节点,并在执行过程中重启任何失败的服务。
Spark 集群管理器有三种类型:
-
Standalone:这是一个简单的集群管理器,与 Spark 一起捆绑提供,并且非常容易设置和使用。
-
Hadoop YARN:YARN(Yet Another Resource Negotiator)是 Hadoop 生态系统附带的一个资源管理器。作为一个数据处理系统,Spark 可以与许多数据存储系统集成。Hadoop 分布式文件系统(HDFS)是大数据行业中应用最广泛的分布式文件系统之一,Spark 与 HDFS 的集成在许多公司中已成为常见的配置。由于 YARN 是 Hadoop 生态系统的一部分,你可以使用相同的资源管理器来管理你的 Spark 资源。
-
Kubernetes:Kubernetes 是一个开源的容器编排系统,用于自动化部署操作、扩展服务以及其他形式的服务器管理。Kubernetes 还能够管理 Spark 集群资源。
-
Spark 驱动程序:Spark 驱动程序是 Spark 应用程序的主要程序。它负责控制应用程序的执行并跟踪节点的不同状态,以及分配给每个节点的任务。该程序可以是任何你运行的脚本,甚至是 Spark 接口。
-
Spark 执行器:Spark 执行器是实际在工作节点上执行计算任务的进程。它们是相当简单的进程,目的是接收分配的任务,计算它,然后将结果发送回 Spark Context。
-
SparkContext:正如其名所示,Spark Context 跟踪执行上下文。Spark 驱动程序执行的任何命令都通过这个上下文。Spark Context 与 Spark 集群管理器通信,以协调正确的执行器执行活动。
Spark 驱动程序是管理集群上操作并行执行的主要功能。驱动程序通过一个称为 弹性分布式数据集(RDD)的数据结构来实现这一点。
理解什么是弹性分布式数据集
Apache Spark 建立在 RDD 的基础上。它是一个容错的数据记录,位于多个节点上且不可变。你在 Spark 中所做的所有操作都是使用 RDD 完成的。由于它是不可变的,因此你进行的任何转换最终都会创建一个新的 RDD。RDD 被划分为逻辑集合,然后这些集合被分配到 Spark 节点上进行执行。Spark 内部处理所有这些分配。
让我们了解 Spark 如何使用 RDD 在规模上进行数据处理。参考以下图表:
图 12.3 – 线性 RDD 转换
因此,RDD 是不可变的,这意味着一旦数据集被创建,就不能对其进行修改。所以,如果你想对数据集进行更改,那么 Spark 将从现有的 RDD 创建一个新的 RDD,并跟踪所做的更改。在这里,你的初始数据存储在RDD 1中,所以你必须假设你需要删除一列并将另一列的类型从字符串转换为数字。Spark 将创建RDD 2,它将包含这些更改,并记录所做的更改。最终,随着你进一步转换数据,Spark 将包含许多 RDD。
你可能会想知道,如果你需要对数据进行许多转换,Spark 是否会创建那么多的 RRD,最终耗尽内存?记住,RDD 是容错的且不可变的,所以如果你从RDD 2创建了RDD 3,那么你只需要保留RDD 2以及从RDD 2到RDD 3的数据转换过程。你将不再需要RDD 1,因此可以将其删除以释放空间。Spark 为你处理所有的内存管理。它将删除任何不再需要的 RDD。
那是一个对简单问题的非常简化的解释。如果你从同一个 RDD 创建多个包含不同转换的 RDD,会怎样?这可以在以下图表中看到:
图 12.4 – 分支 RDD 转换
在这种情况下,你需要保留所有 RDD。这就是 Spark 的延迟评估发挥作用的地方。延迟评估是一种评估技术,其中评估表达式被延迟到结果值需要时才进行。让我们通过查看 RDD 操作来更好地理解这一点。有两种类型的操作:
-
转换:转换是产生新 RDD 的操作,该 RDD 基于包含数据集更改的现有 RDD。这些操作主要是由将原始数据集转换为可以用于提取评估指标或其他过程的精炼最终数据集的数据操作组成。这主要涉及如并集操作或分组操作之类的数据操作。
-
动作:动作是接受 RDD 作为输入但不生成新 RDD 作为输出的操作。从动作操作中导出的输出值被发送回驱动程序。这通常涉及如 count(返回 RDD 中元素的数量)或 aggregate(对 RDD 的内容执行聚合操作并将结果发送回)之类的操作。
转换操作是惰性的。当在 RDD 上执行转换操作时,Spark 会记录需要执行的操作,但不会立即执行。它只有在接收到动作操作时才会开始转换过程,因此得名惰性评估。
让我们用一个简单的例子来理解整个过程。假设你有一个包含一家公司所有员工原始数据集的 RDD,你想计算所有高级机器学习工程师的平均工资。你的转换操作是将所有机器学习工程师过滤到 RDD 2,然后进一步按资历过滤到 RDD 3。当你将这个转换操作传递给 Spark 时,它不会创建 RDD 3。它只会记录下来。当它接收到动作操作——即计算平均工资——这时惰性评估开始发挥作用,Spark 开始执行转换,并最终执行动作。
惰性评估帮助 Spark 理解执行动作操作所需的转换操作,并找到在考虑空间复杂性的同时进行转换的最有效方式。
小贴士
Spark 是一种非常复杂且强大的技术。它提供了大量的灵活性,可以根据不同的数据处理需求进行配置。在本章中,我们只是探索了 Apache Spark 的冰山一角。如果你对了解 Spark 的全部功能感兴趣,我强烈建议你探索 Apache Spark 文档,可以在 spark.apache.org/
找到。
现在我们对 Spark 的工作原理有了基本的了解,让我们来了解 H2O Sparkling Water 如何结合 H2O 和 Spark。
探索 H2O Sparkling Water
Sparkling Water 是一个结合了 H2O 快速且可扩展的机器学习功能与 Apache Spark 分析能力的 H2O 产品。这两种技术的结合使用户能够进行数据清洗的 SQL 查询,将结果输入 H2O 进行模型训练,构建和部署模型到生产环境,然后用于预测。
H2O Sparkling Water 是设计成可以在常规 Spark 应用程序中运行 H2O 的。它提供了在 Spark 执行器内部运行 H2O 服务器的能力,这样 H2O 服务器就可以访问存储在执行器中的所有数据,以执行任何基于机器学习的计算。
H2O 和 Spark 之间的透明集成提供了以下好处:
-
H2O 算法,包括 AutoML,可以在 Spark 工作流程中使用
-
应用特定的数据结构可以在 H2O 和 Spark 之间进行转换和支持
-
你可以使用 Spark RDDs 作为 H2O ML 算法的数据集
Sparkling Water 支持两种类型的后端:
- 内部后端:在这种配置中,一旦初始化 H2O 上下文,H2O 应用就在 Spark executor 内部启动。然后,H2O 通过在每个 executor 内部初始化其键值存储和内存管理器来启动其服务。部署 H2O Sparkling Water 作为内部后端很容易,但如果 Spark 的集群管理器决定关闭任何 executor,那么在该 executor 中运行的 H2O 服务器也会关闭。内部后端是 H2O Sparkling Water 使用的默认设置。内部运行的 H2O Sparkling Water 架构如下所示:
图 12.5 – Sparkling Water 内部后端架构
如您所见,H2O 服务位于每个 Spark executor 内部。
- 外部后端:在这种配置中,H2O 服务与 Spark executor 分开部署,H2O 服务器和 Spark executor 之间的通信由 Spark driver 处理。作为外部后端的 H2O Sparkling Water 架构如下所示:
图 12.6 – Sparkling Water 外部后端架构
如您所见,H2O 集群是独立于 Spark executor 运行的。这种分离有好处,因为 H2O 集群不再受 Spark Executor 关闭的影响。然而,这也增加了 H2O driver 需要协调 H2O 集群和 Spark Executor 之间通信的开销。
Sparkling Water 虽然建立在 Spark 之上,但在使用 Sparkling Water 集群中的 H2O 服务器进行计算时,使用 H2OFrame。因此,Spark RDD 和 H2OFrame 之间存在大量的数据交换和交互。
DataFrame 之间的转换如下所示:
-
H2OFrame 转换为 RDD:当将 H2OFrame 转换为 RDD 时,Sparkling Water 不是重新创建数据为不同类型,而是在 H2OFrame 周围创建一个包装器,该包装器类似于 RDD API。这个包装器将所有基于 RDD 的操作解释为相同的 H2OFrame 操作。
-
RDD 转换为 H2OFrame:将 RDD 转换为 H2OFrame 涉及评估 RDD 中的数据,然后将其转换为 H2OFrame。然而,H2OFrame 中的数据被高度压缩。H2O 和 Spark 之间共享的数据取决于部署时使用的后端类型。
-
内部 Sparkling Water 后端的数据共享:在内部 Sparkling Water 后端,由于 H2O 服务是在 Spark Executor 内部启动的,因此 Spark 服务和 Executor 内部的 H2O 服务都使用相同的Java 虚拟机(JVM),因此数据对两个服务都是可访问的。以下图表显示了内部 Sparkling Water 后端的数据共享过程:
图 12.7 – 内部 Sparkling Water 后端的数据共享
由于这两个服务都在同一个 executor 上,您在转换两种类型之间的 DataFrames 时需要考虑内存。您需要为 Spark 和 H2O 执行各自的操作分配足够的内存。Spark 需要您数据集的最小内存,以及您希望执行的任何转换的额外内存。此外,将 RDD 转换为 H2OFrames 会导致数据重复,因此建议使用 4 倍更大的数据集用于 H2O。
- 外部 Sparkling Water 后端的数据共享:在外部 Sparkling Water 后端,H2O 服务是在一个与 Spark Executor 分开的集群中启动的。因此,在网络上从一个集群传输数据到另一个集群会有额外的开销。以下图表应该能帮助您理解这一点:
图 12.8 – 外部 Sparkling Water 后端的数据共享
由于这两个服务都位于它们自己的集群中(如果您为各自的集群分配了足够的内存),您不需要担心内存限制。
小贴士
H2O Sparkling Water 可以在各种平台上以各种方式运行。如果您想了解更多关于您可以部署 H2O Sparkling Water 的各种方式,以及获取更多有关其后端的信息,请随时查看docs.h2o.ai/sparkling-water/3.2/latest-stable/doc/design/supported_platforms.xhtml
。
现在我们已经了解了 H2O Sparkling Water 是如何工作的,让我们看看我们如何下载和安装它。
下载和安装 H2O Sparkling Water
在您可以在系统上安装 H2O Sparkling Water 之前,H2O Sparkling Water 有一些特定的要求需要满足。H2O Sparkling Water 版本 3.36 的安装要求如下:
-
操作系统:H2O Sparkling Water 仅支持 Linux、macOS 和 Windows。
-
Java 版本:H2O Sparkling Water 支持所有高于 Java 1.8 的 Java 版本。
-
Python 版本:如果您计划使用 Sparkling Water 的 Python 版本,即 PySparkling,那么您需要在系统上安装一个高于 3.6 的 Python 版本。
-
H2O 版本:H2O Sparkling Water 版本 3.36.1 需要与您系统上安装的 H2O 相同版本。然而,H2O Sparkling Water 已经预包装了一个兼容的 H2O 版本,因此您不需要单独安装 H2O 来使用 H2O Sparkling Water。
-
Spark 版本:H2O Sparkling Water 版本 3.36.1 严格支持 Spark 3.2。任何高于或低于 3.2 版本的 Spark 版本可能会导致安装问题或 H2O Sparkling Water 的工作问题。Spark 3.2 有其自己的依赖项,如下所示:
-
Java 版本:Spark 3.2 严格支持 Java 8 和 Java 11
-
Scala 版本:Spark 3.2 严格运行在 Scala 2.12/2.13 上
-
R 版本:Spark 3.2 支持任何高于 3.5 的 R 版本
-
Python 版本:Spark 3.2 支持任何高于 3.6 的 Python 版本
-
-
将
SPARK_HOME
环境变量设置为指向您的本地 Spark 3.2 安装。
现在,让我们设置我们的系统,以便我们可以下载和安装 H2O Sparkling Water。按照以下步骤设置 H2O Sparkling Water:
-
我们将首先安装 Java 11,这是 Spark 和 H2O Sparkling Water 所需的。尽管 Spark 也支持 Java 8,但建议使用 Java 11,因为它是一个更新的版本,具有改进和安全性补丁。您可以通过执行以下命令来下载和安装 Java 11:
sudo apt-get install openjdk-11-jdk
-
如果您希望使用 PySparkling Python 解释器,则可以安装 Python 版本 3.10。您可以通过执行以下命令来实现:
sudo apt install python3
-
现在我们已经安装了基本语言,接下来我们继续下载并安装 Spark 版本 3.2。您可以从 Apache 软件基金会官方下载页面(https://www.apache.org/dyn/closer.lua/spark/spark-3.2.1/spark-3.2.1-bin-hadoop3.2.tgz)下载 Spark 的特定版本,或者直接在您的终端中运行以下命令:
wget https://downloads.apache.org/spark/spark-3.1.2/spark-3.1.2-bin-hadoop3.2.tgz
如果您正在使用Maven 项目,则可以直接指定 Spark 核心 Maven 依赖项,如下所示:
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.13</artifactId>
<version>3.1.2</version>
</dependency>
您可以在mvnrepository.com/artifact/org.apache.spark/spark-core
找到 Spark 的 Maven 仓库。
-
然后,您可以在终端中执行以下命令来解压缩
.tar
文件:sudo tar xzvf spark-*
-
现在我们已经提取了 Spark 的二进制文件,接下来我们设置环境变量,如下所示:
export SPARK_HOME="/path/to/spark/installation"
-
我们还必须将
MASTER
环境变量设置为local[*]
以启动一个本地 Spark 集群:export MASTER="local[*]"
-
现在我们已经安装并准备好了 H2O Sparkling Water 的所有依赖项,接下来我们继续下载 H2O Sparkling Water。您可以从
h2o.ai/products/h2o-sparkling-water/
下载最新版本。点击下载最新版按钮后,您应该会被重定向到 H2O Sparkling Water 仓库网站,在那里您可以下载 H2O Sparkling Water 版本3.36的 ZIP 文件。 -
下载完成后,您可以在终端中执行以下命令来解压 ZIP 文件:
unzip sparkling-water-*
-
您可以通过在 Sparkling Water 安装文件夹内执行以下命令来启动 H2O Sparkling Water shell,以检查一切是否正常工作:
bin/sparkling-shell
-
通过这样做,您可以通过在 Spark 集群内启动一个 H2O 云来查看 Sparkling Water 是否已与 Spark 集成。您可以在
sparkling-shell
内部执行以下命令来实现:import ai.h2o.sparkling._ val h2oContext = H2OContext.getOrCreate()
您应该会得到以下类似的输出:
图 12.9 – 成功启动 H2O Sparkling Water
现在我们已成功下载并安装了 Spark 和 H2O Sparkling Water,并确保它们都能正常工作,根据 H2O.ai 的文档,还有一些通用的推荐调整您必须进行。让我们看一下:
-
在启动 Sparkling shell 时,增加 Spark 驱动器和 Spark 执行器的可用内存,从
config
参数的默认值:bin/sparkling-shell --conf spark.executor.memory=4g spark.driver.memory=4g
如果您使用 YARN 或您的集群管理器,则使用config spark.yarn.am.memory
而不是spark.driver.memory
。您还可以通过在spark-defaults.conf
文件中设置这些值来将这些值设置为默认配置属性。这些可以在您的 Spark 安装文件中找到。
-
除了集群内存外,还建议增加 Spark 节点的 PermGen 大小。默认的 PermGen 大小通常非常小,可能导致
OutOfMemoryError
。以下为spark.driver.extraJavaOptions
和spark.executor.extraJavaOptions
配置选项:bin/sparkling-shell --conf spark.driver.extraJavaOptions -XX:MaxPermSize=384 -XX:PermSize=384m spark.executor.extraJavaOptions -XX:MaxPermSize=384 -XX:PermSize=384m
-
还建议保持您的集群同质化——也就是说,Spark 驱动器和执行器分配的资源数量相同。
-
以下配置也被推荐以加快和稳定在 Spark 集群上创建 H2O 服务:
-
增加在数据本地模式下启动的任务等待秒数,以便 H2O 任务在本地使用数据进行处理。您可以按以下方式设置:
bin/sparkling-shell --conf spark.locality.wait=3000
-
强制 Spark 仅在分配了 100%的资源后才开始调度作业:
bin/sparkling-shell --conf spark.scheduler.minRegisteredResourcesRatio=1
-
不要重试失败的任务:
bin/sparkling-shell --conf spark.task.maxFailures=1
-
将每个执行器心跳之间的间隔设置为小于 Spark 的网络超时时间(即
spark.network.timeout
),其默认值为120 秒。因此,将心跳值设置为约10 秒:bin/sparkling-shell --conf spark.executor.heartbeatInterval=10s
-
现在我们已适当地配置了 Spark 和 H2O Sparkling Water,让我们看看如何使用这些技术通过 Spark 和 H2O AutoML 解决 ML 问题。
使用 H2O Sparkling Water 实现 Spark 和 H2O AutoML
对于这个实验,我们将使用混凝土抗压强度数据集。您可以在 https://archive.ics.uci.edu/ml/datasets/Concrete+Compressive+Strength 找到这个数据集。
关于数据集的更多详细信息:I-Cheng Yeh,使用人工神经网络模拟高性能混凝土强度,水泥与混凝土研究,第 28 卷,第 12 期,第 1797-1808 页(1998 年)。
让我们先了解我们将要解决的问题陈述。
理解问题陈述
混凝土抗压强度数据集是一个包含以下特征的1,030个数据点的数据集:
-
水泥: 此功能表示混合物每立方米的混凝土量(以千克计)
-
高炉渣: 此功能表示混合物每立方米的渣量(以千克计)
-
粉煤灰: 此功能表示混合物每立方米的粉煤灰量(以千克计)
-
水:这个特征表示混合物中添加的水的量,单位为千克/立方米
-
高效减水剂:这个特征表示混合物中添加的高效减水剂的量,单位为千克/立方米
-
粗集料:这个特征表示混合物中添加的粗集料(换句话说,石头)的量,单位为千克/立方米
-
细集料:这个特征表示混合物中添加的细集料(换句话说,沙子)的量,单位为千克/立方米
-
年龄:这个特征表示水泥的年龄
-
混凝土抗压强度:这个特征表示混凝土的抗压强度,单位为兆帕(MPa)
机器学习问题是要使用所有特征来预测混凝土的抗压强度。
数据集的内容如下:
图 12.10 – 混凝土抗压强度数据集样本
那么,让我们看看我们如何使用 H2O Sparkling Water 解决这个问题。首先,我们将学习如何使用 H2O AutoML 和 Spark 来训练模型。
在 Sparkling Water 中运行 AutoML 训练
一旦成功安装了 Spark 3.2 和 H2O Sparkling Water,以及设置了正确的环境变量(SPARK_HOME
和MASTER
),你就可以开始模型训练过程了。
按照以下步骤操作:
-
通过在 H2O Sparkling Water 提取文件夹中执行命令来启动 Sparkling shell:
./bin/sparkling-shell
这应该在你的终端中启动一个 Scala shell。输出应该如下所示:
图 12.11 – H2O Sparkling Water 的 Scala shell
你也可以使用PySparkling
shell 在 Python 中执行相同的实验。你可以通过执行以下命令来启动PySparkling
shell:
./bin/PySparkling
你应该得到以下类似的输出:
图 12.12 – H2O Sparkling Water 的 Python shell
-
现在,我们需要在 Spark 环境中启动一个 H2O 集群。我们可以通过创建一个 H2OContext 并执行其
getOrCreate()
函数来实现这一点。因此,在你的 Sparkling shell 中执行以下代码来导入必要的依赖项并执行 H2O 上下文代码:import ai.h2o.sparkling._ import java.net.URI val h2oContext = H2OContext.getOrCreate()
在 PySparkling shell 中,代码将如下所示:
from PySparkling import *
h2oContext = H2OContext.getOrCreate()
你应该得到以下类似的输出,表明你的 H2O 上下文已创建:
图 12.13 – 成功创建 H2O 上下文
-
现在,我们必须确保我们的混凝土抗压强度数据集可以通过 Spark 内置的文件 I/O 系统在每一个节点上下载。因此,执行以下命令来导入你的数据集:
import org.apache.spark.SparkFiles spark.sparkContext.addFile("/home/salil/Downloads/Concrete_Data.csv")
在 PySparkling shell 中,我们必须使用 H2O 的import
函数导入数据集。Python 代码将如下所示:
import h2o
h2oFrame = h2o.import_file("/home/salil/Downloads/Concrete_Data.csv")
-
添加后,我们必须通过在 Scala shell 中执行以下命令将数据集解析为 Spark DataFrame:
val sparkDataFrame = spark.read.option("header", "true").option("inferSchema", "true").csv(SparkFiles.get("Concrete_Data.csv"))
在 PySparkling shell 中,等效的代码如下:
sparkDataFrame = hc.asSparkFrame(h2oFrame)
-
现在,
sparkDataFrame
包含了作为 Spark DataFrame 的数据集。因此,让我们在它上面执行训练-测试拆分,将 DataFrame 拆分为测试和训练 DataFrame。您可以在 Sparkling shell 中执行以下命令:val Array(trainingDataFrame, testingDataFrame) = sparkDataFrame.randomSplit(Array(0.7, 0.3), seed=123)
在 PySparkling shell 中,执行以下命令:
[trainingDataFrame, testingDataFrame] = sparkDataFrame.randomSplit([0.7, 0.3], seed=123)
-
现在我们有了
trainingDataFrame
和testingDataFrame
,分别用于训练和测试。让我们创建一个 H2OAutoML 实例,在trainingDataFrame
上自动训练模型。执行以下命令以实例化 H2O AutoML 对象:import ai.h2o.sparkling.ml.algos.H2OAutoML val aml = new H2OAutoML()
在 PySparkling 中,当初始化 H2O AutoML 对象时,我们也会设置标签列。相应的代码如下:
from PySparkling.ml import H2OAutoML
aml = H2OAutoML(labelCol=" Concrete compressive strength ")
-
让我们看看如何在 Scala shell 中设置数据集的标签,以便 AutoML 对象知道 DataFrame 中哪些列是要预测的。执行以下命令:
aml.setLabelCol("Concrete compressive strength")
H2O 将将 DataFrame 的所有列视为特征,除非明确指定。然而,它将忽略设置为 标签、折叠列、权重或任何其他明确设置为忽略的列。
H2O AutoML 根据响应列的类型区分回归和分类问题。如果响应列是字符串,那么 H2O AutoML 假设它是一个 ai.h2o.sparkling.ml.algos.classification.H2OAutoMLClassifier
对象或 ai.h2o.sparkling.ml.algos.regression.H2OAutoMLRegressor
对象,而不是我们在这个例子中使用的 ai.h2o.sparkling.ml.algos.H2OautoML
。
-
现在,让我们将 AutoML 模型训练限制为仅 10 个模型。执行以下命令:
aml.setMaxModels(10)
此代码的等效 Python 语法相同,因此请在您的 PySparkling shell 中执行此相同命令。
-
一旦我们设置了所有 AutoML 对象,剩下的唯一事情就是触发训练。为此,执行以下命令:
val model = aml.fit(trainingDataFrame)
相当于 Python 的代码如下:
model = aml.fit(trainingDataFrame)
一旦训练完成,您应该得到以下类似的结果:
图 12.14 – H2O AutoML 在 H2O Sparkling Water 中的结果
如您所见,我们得到了一个堆叠集成模型作为主模型,其下方是模型键。在 模型键 下方是 模型摘要,其中包含训练和交叉验证的指标。
正如我们在 第二章 中所做的那样,使用 H2O Flow (H2O 的 Web UI),我们没有为 aml
对象设置排序指标,因此默认情况下,H2O AutoML 将使用默认指标。这将默认为 deviance
,因为它是 automl.setSortMetric()
并传入您选择的排序指标。
-
您还可以通过使用
getModelDetails()
函数来获取模型的详细视图。执行以下命令:model.getModelDetails()
此命令在 PySparkling 和 Scala shell 中都适用,并将输出关于模型元数据的非常详细的 JSON。
-
您还可以通过执行以下命令来查看 AutoML 排行榜:
val leaderboard = aml.getLeaderboard() leaderboard.show(false)
PySparkling shell 的等效 Python 代码如下:
leaderboard = aml.getLeaderboard("ALL")
leaderboard.show(truncate = False)
你应该得到以下类似的输出:
图 12.15 – H2O AutoML 在 H2O Sparkling Water 中的排行榜
这将显示包含所有已训练并按排序指标排名的模型的排行榜。
-
使用 H2O Sparkling Water 进行预测也非常简单。预测功能被封装在一个简单易用的包装函数
transform
中。执行以下代码以对测试 DataFrame 进行预测:model.transform(testingDataFrame).show(false)
在 PySparkling shell 中,情况略有不同。在这里,你必须执行以下代码:
model.transform(testingDataFrame).show(truncate = False)
你应该得到以下类似的输出:
图 12.16 – 将预测结果与测试 DataFrame 结合
transform
函数的输出显示了右侧带有两个额外列的整个 testDataFrame,这两个列分别称为 detailed_prediction 和 prediction。
-
现在,让我们下载这个模型作为 MOJO,以便我们可以在下一个实验中使用它,我们将看到 H2O Sparkling Water 如何加载和使用 MOJO 模型。执行以下命令:
model.write.save("model_dir")
该命令对 Scala 和 Python shell 都相同,应将模型 MOJO 下载到指定的路径。如果你使用 Hadoop 文件系统作为 Spark 数据存储引擎,则默认使用 HDFS。
现在我们知道了如何使用 H2O Sparkling Water 导入数据集、训练模型和进行预测,让我们更进一步,看看我们如何通过将它们加载到 H2O Sparkling Water 中并对它们进行预测来重用现有的模型二进制文件,也称为 MOJOs。
在 H2O Sparkling Water 中使用模型 MOJOs 进行预测
当你使用 H2O Sparkling Water 训练模型时,生成的模型总是 MOJO 类型。H2O Sparkling Water 可以加载由 H2O-3 生成的模型 MOJOs,并且与不同版本的 H2O-3 兼容。你不需要创建 H2O 上下文来使用模型 MOJOs 进行预测,但你确实需要一个评分环境。让我们通过完成一个实验来理解这一点。
按照以下步骤操作:
-
要使用导入的模型 MOJOs 进行预测,你需要一个评分环境。我们可以通过两种方式创建评分环境;让我们看看:
- 使用 Sparkling Water 准备好的脚本,这些脚本设置了加载 MOJOs 并在 Spark 类路径上对其进行预测所需的全部依赖项。请参考以下命令:
以下命令适用于 Scala shell:
./bin/spark-shell --jars jars/sparkling-water-assembly-scoring_2.12-3.36.1.3-1-3.2-all.jar
以下命令适用于 Python shell:
./bin/pyspark --py-files py/h2o_PySparkling_scoring_3.2-3.36.1.3-1-3.2.zip
-
直接使用 Spark 并手动设置依赖项。
-
一旦我们设置了评分环境,我们就可以加载模型 MOJO。加载到 Sparkling Water 中的模型 MOJO 是不可变的。因此,一旦加载了模型,就无法进行任何配置更改。然而,你可以在加载模型之前设置配置。你可以通过使用
H2OMOJOSettings()
函数来实现这一点。请参考以下示例:import ai.h2o.sparkling.ml.models._ val modelConfigurationSettings = H2OMOJOSettings(convertInvalidNumbersToNa = true, convertUnknownCategoricalLevelsToNa = true)
对于 PySparkling,请参考以下代码:
from PySparkling.ml import *
val modelConfigurationSettings = H2OMOJOSettings(convertInvalidNumbersToNa = true, convertUnknownCategoricalLevelsToNa = true)
-
一旦设置了配置设置,你可以使用
H2OMOJOModel
库中的createFromMojo()
函数加载模型 MOJO。因此,执行以下代码加载你在 Sparkling Water 中运行 AutoML 训练 部分创建的模型 MOJO 并传递配置设置:val loadedModel = H2OMOJOModel.createFromMojo("model_dir/model_mojo", modelConfigurationSettings)
Python 的等效代码如下:
loadedModel = H2OMOJOModel.createFromMojo("model_dir/ model_mojo", modelConfigurationSettings)
如果你指定模型 MOJO 路径为相对路径并且启用了 HDFS,Sparkling Water 将检查 HDFS 主目录;否则,它将从当前目录中搜索。你也可以传递一个指向你的模型 MOJO 文件的绝对路径。
你也可以手动指定你想要加载模型 MOJO 的位置。对于 HDFS 文件系统,你可以使用以下命令:
loadedModel = H2OMOJOModel.createFromMojo("hdfs:///user/salil/ model_mojo")
对于本地文件系统,你可以使用以下命令:
loadedModel = H2OMOJOModel.createFromMojo("file:///Users/salil/some_ model_mojo")
-
一旦成功加载,你可以直接使用模型进行预测,就像我们在 Sparkling Water 中运行 AutoML 训练 部分所做的那样。因此,执行以下命令使用你最近加载的模型 MOJO 进行预测:
val predictionResults = loadedModel.transform(testingDataframe)
-
预测结果存储为另一个 Spark DataFrame。因此,要查看预测值,我们只需执行以下命令来显示预测结果:
predictionResults.show()
你应该得到以下类似的输出:
图 12.17 – 模型 MOJO 的预测结果
如你所见,我们在加载 MOJO 时特别将 withDetailedPredictionCol
设置为 False
。这就是为什么我们看不到预测结果中的详细 _prediction_column
。
小贴士
在将 H2O 模型 MOJO 加载到 Sparkling Water 时,你可以设置许多配置。对于 MOJO 模型,也有额外的可用方法,可以帮助收集更多关于你的模型 MOJO 的信息。所有这些详细信息都可以在 H2O 的官方文档页面上找到:docs.h2o.ai/sparkling-water/3.2/latest-stable/doc/deployment/load_mojo.xhtml#loading-and-usage-of-h2o-3-mojo-model
。
恭喜你 – 你刚刚学会了如何使用 H2O Sparkling Water 将 Spark 和 H2O AutoML 结合使用。
摘要
在本章中,我们学习了如何使用 H2O Sparkling Water 系统中的 H2O AutoML 与 Apache Spark 结合使用。我们首先了解了 Apache Spark 是什么。我们调查了构成 Spark 软件的各种组件。然后,我们深入研究了其架构,并了解了它是如何使用计算机集群来执行数据分析的。我们还调查了 Spark 集群管理器、Spark 驱动程序、Executor 以及 Spark Context。然后,我们进一步深入研究了 RDDs,并了解了 Spark 是如何使用它们在数据集上的转换操作上执行懒加载评估的。我们还了解到,Spark 足够智能,能够高效地管理其资源,并在操作期间删除任何未使用的 RDD。
在掌握了 Spark 的相关知识的基础上,我们开始探索 H2O Sparkling Water 是什么,以及它是如何在一个无缝集成的系统中结合使用 Spark 和 H2O 的。然后,我们深入研究了其架构,并了解了可以用来部署系统的两种后端类型。我们还了解了它是如何处理 Spark 和 H2O 之间的数据交换的。
一旦我们对 H2O Sparkling Water 有了清晰的认识,我们就开始实际使用该系统的实施。我们学习了如何下载和安装系统以及它运行顺畅所需的严格依赖项。我们还探索了 H2O.ai 在启动 H2O Sparkling Water 时推荐的各种配置调整。一旦系统启动并运行,我们进行了一个实验,使用混凝土抗压强度数据集,通过 H2O Sparkling Water 对混凝土的抗压强度进行预测。我们将数据集导入 Spark 集群,使用 H2O AutoML 进行自动机器学习,并使用领先模型进行预测。最后,我们学习了如何将模型 MOJOs 导出和导入到 H2O Sparkling Water 中,并使用它们进行预测。
在下一章中,我们将探讨 H2O.ai 进行的一些案例研究,了解企业如何在实际应用中实施 H2O,以及 H2O 如何帮助他们解决机器学习问题。
第十三章:使用 H2O AutoML 与其他技术
在前几章中,我们一直在探讨如何在生产环境中使用 H2O AutoML。我们看到了如何使用 H2O 模型作为 POJOs 和 MOJOs 作为可移植对象来进行预测。然而,在实际的生产环境中,您通常会使用多种技术来满足各种技术要求。这些技术的协作在您系统的无缝功能中起着重要作用。
因此,了解我们如何将 H2O 模型与其他在机器学习领域中常用的技术协作使用非常重要。在本章中,我们将探索和实现 H2O 与这些技术中的一些,并查看我们如何构建可以协同工作以提供协作优势的系统。
首先,我们将研究如何使用 Spring Boot 应用程序将 H2O 预测服务托管为网络服务。然后,我们将探讨如何使用 H2O 和 Apache Storm 进行实时预测。
本章将涵盖以下主题:
-
使用 H2O AutoML 和 Spring Boot
-
使用 H2O AutoML 和 Apache Storm
到本章结束时,您应该对如何使用使用 H2O AutoML 训练的模型与不同技术结合,在不同场景中进行预测有更好的理解。
技术要求
对于本章,您需要以下内容:
-
您首选的网页浏览器的最新版本。
-
您选择的 集成开发环境(IDE)。
-
本章中进行的所有实验都是在 Ubuntu Linux 系统上的 IntelliJ IDE 中完成的。您可以使用相同的设置跟随操作,或者使用您熟悉的 IDE 和操作系统执行相同的实验。
本章的所有代码示例都可以在 GitHub 上找到,网址为 github.com/PacktPublishing/Practical-Automated-Machine-Learning-on-H2O/tree/main/Chapter%2013
。
让我们直接进入第一部分,我们将学习如何将使用 H2O AutoML 训练的模型托管在 Spring Boot 创建的 Web 应用程序上。
使用 H2O AutoML 和 Spring Boot
在当今时代,大多数创建的软件服务都托管在互联网上,它们可以通过托管在 Web 服务器上的 Web 应用程序对所有互联网用户开放。所有这些都是在使用 Web 应用程序完成的。即使是使用机器学习的预测服务也可以通过托管在 Web 应用程序上向公众提供。
Spring 框架是最常用的开源 Web 应用框架之一,用于创建网站和 Web 应用。它基于 Java 平台,因此可以在任何具有 JVM 的系统上运行。Spring Boot是 Spring 框架的扩展,它提供了预配置的 Web 应用设置。这有助于你快速设置 Web 应用,无需实现配置和托管 Web 服务所需的底层管道。
因此,让我们通过理解问题陈述来深入了解实现。
理解问题陈述
假设你正在为一家葡萄酒制造公司工作。官员们有一个要求,他们希望自动化计算葡萄酒品质及其颜色的过程。该服务应作为一个 Web 服务提供,质量保证主管可以提供一些关于葡萄酒特性的信息,该服务使用这些细节和底层 ML 模型来预测葡萄酒的品质及其颜色。
因此,从技术上讲,我们需要两个模型来完成完整的预测。一个将是预测葡萄酒品质的回归模型,另一个将是预测葡萄酒颜色的分类模型。
我们可以使用红葡萄酒品质和白葡萄酒品质数据集的组合,并在其上运行 H2O AutoML 来训练模型。你可以在 https://archive.ics.uci.edu/ml/datasets/Wine+Quality 找到数据集。组合数据集已存在于github.com/PacktPublishing/Practical-Automated-Machine-Learning-on-H2O/tree/main/Chapter%2013/h2o_spring_boot/h2o_spring_boot
。
下面的截图显示了数据集的一个样本:
图 13.1 – 葡萄酒品质和颜色数据集
此数据集包含以下特征:
-
固定酸度:这个特征解释了非挥发性酸度的量,意味着它不会在特定时间内蒸发。
-
挥发性酸度:这个特征解释了挥发性酸度的量,意味着它会在特定时间内蒸发。
-
柠檬酸:这个特征解释了葡萄酒中柠檬酸的量。
-
残留糖分:这个特征解释了葡萄酒中残留糖分的量。
-
氯化物:这个特征解释了葡萄酒中氯化物的数量。
-
游离二氧化硫:这个特征解释了葡萄酒中游离二氧化硫的量。
-
总二氧化硫:这个特征解释了葡萄酒中总二氧化硫的量。
-
密度:这个特征解释了葡萄酒的密度。
-
pH 值:这个特征解释了葡萄酒的 pH 值,其中 0 是最酸性的,14 是最碱性的。
-
硫酸盐: 此功能解释了葡萄酒中存在的硫酸盐数量。
-
酒精: 此功能解释了葡萄酒中存在的酒精含量。
-
质量: 这是响应列,记录了葡萄酒的质量。0 表示葡萄酒非常差,而 10 表示葡萄酒非常好。
-
颜色: 此功能代表葡萄酒的颜色。
现在我们已经理解了问题陈述和我们将要处理的数据集,让我们设计架构以展示这个网络服务的工作方式。
设计架构
在我们深入服务实施之前,让我们看看所有技术应该如何协同工作的整体架构。以下是我们葡萄酒质量和颜色预测网络服务的架构图:
图 13.2 – 葡萄酒质量和颜色预测网络服务的架构
让我们了解这个架构的各个组成部分:
-
客户端: 这是指使用应用程序的人——在这种情况下,是葡萄酒质量保证执行者。客户端通过向其发送 POST 请求并与网络应用程序通信,传递葡萄酒的属性,并获取葡萄酒的质量和颜色作为预测响应。
-
Spring Boot 应用程序: 这是运行在网络服务器上的网络应用程序,负责执行计算过程。在我们的场景中,这是将接受客户端 POST 请求的应用程序,将数据输入到模型中,获取预测结果,并将结果作为响应发送回客户端。
-
Tomcat Web 服务器: 网络服务器仅仅是处理互联网上 HTTP 通信的软件和硬件。在我们的场景中,我们将使用 Apache Tomcat 网络服务器。Apache Tomcat 是一个用 Java 编写的免费开源 HTTP 网络服务器。网络服务器负责将客户端请求转发到网络应用程序。
-
使用
h2o-genmodel
库进行预测。 -
H2O 服务器: 将使用 H2O 服务器来训练模型。正如我们在第一章中看到的,理解 H2O AutoML 基础知识,我们可以在 H2O 服务器上运行 H2O AutoML。我们将通过启动 H2O 服务器,使用 H2O AutoML 训练模型,然后下载训练好的模型作为 POJOs,以便我们可以将它们加载到 Spring Boot 应用程序中。
-
数据集: 这是用于训练我们的模型的葡萄酒质量数据集。如前所述,此数据集是红葡萄酒质量和白葡萄酒质量数据集的组合。
现在我们已经很好地理解了我们将如何创建我们的葡萄酒质量和颜色预测网络服务,让我们继续到其实施部分。
在实施工作中
此服务已经构建完成,可在 GitHub 上找到。代码库可以在 github.com/PacktPublishing/Practical-Automated-Machine-Learning-on-H2O/tree/main/Chapter%2013/h2o_spring_boot
找到。
在我们深入代码之前,请确保您的系统满足以下最低要求:
-
Java 版本 8 及以上
-
Maven 的最新版本,最好是 3.8.6 版本
-
Python 版本 3.7 及以上
-
使用 pip3 安装的 H2O Python 库
-
系统上已安装的 Git
首先,我们将克隆 GitHub 仓库,在我们的首选 IDE 中打开它,并查看文件以了解整个过程。以下步骤已在 Ubuntu 22.04 LTS 上执行,我们使用 IntelliJ IDEA 版本 2022.1.4 作为 IDE。请随意使用任何支持 Maven 和 Spring 框架的 IDE 以获得更好的支持。
因此,克隆 GitHub 仓库并导航到 Chapter 13/h2o_spring_boot/
。然后,你启动你的 IDE 并打开项目。一旦你打开了项目,你应该得到一个类似于以下目录结构的结构:
图 13.3 – h2o_wine_predictor 的目录结构
目录结构包括以下重要文件:
-
pom.xml
: 项目对象模型(POM)是 Maven 构建自动化工具的基本单元。它是一个包含所有所需依赖项信息以及正确构建应用程序所需配置的 XML 文件。 -
script.py
: 这是我们将用于在葡萄酒质量数据集上训练模型的 Python 脚本。该脚本启动 H2O 服务器实例,导入数据集,然后运行 AutoML 来训练模型。我们将在稍后更详细地查看它。 -
src/main/java/com.h2o_wine_predictor.demo/api/PredictionController.java
: 这是一个控制器文件,它具有将 POST 请求映射到执行映射函数的请求映射。该函数最终调用实际的业务逻辑,在 ML 模型中进行预测,并将响应发送回去。 -
src/main/java/com.h2o_wine_predictor.demo/service/PredictionService.java
: 这是实际存放预测业务逻辑的文件。这个函数导入 POJO 模型和 h2o-genmodel 库,并使用它们来预测从控制器接收到的数据。 -
src/main/java/com.h2o_wine_predictor.demo/Demo
: 这是 Spring Boot 应用程序的主函数。如果你想启动 Spring Boot 应用程序,你必须执行这个主函数,它会启动 Apache Tomcat 服务器,该服务器承载着网络应用程序。 -
src/main/resources/winequality-combined.csv
: 这是实际 CSV 数据集存储的地方。训练 H2O 模型的 Python 脚本从这个路径选择数据集并开始训练模型。
你可能已经注意到,我们在这个目录中没有找到任何模型 POJO 文件。所以,让我们构建这些文件。参考 script.py
Python 文件,让我们逐行了解正在做什么。
script.py
的代码如下:
-
脚本首先导入依赖项:
import h2o import shutil from h2o.automl import H2OautoML
-
导入完成后,脚本初始化 H2O 服务器:
h2o.init()
-
一旦 H2O 服务器启动并运行,脚本将从
src/main/resources
目录导入数据集:wine_quality_dataframe = h2o.import_file(path = "sec/main/resources/winequality_combined.csv")
-
由于列颜色是分类的,脚本将其设置为
factor
:wine_quality_dataframe["color"] = wine_quality_dataframe["color"].asfactor()
-
最后,你将需要一个用于训练和验证的 DataFrame,以便在训练过程中训练和验证你的模型。因此,脚本还将 DataFrame 分割成 70/30 的比例:
train, valid = wine_quality_dataframe.split_frame(ratios=[.7])
-
现在数据框已经准备好了,我们可以开始训练第一个模型,这是一个用于分类葡萄酒颜色的分类模型。因此,脚本设置了标签和特征,如下所示:
label = "color" features = ["fixed acidity", "volatile acidity", "citric acid", "residual sugar", "chlorides", "free sulfur dioxide", "total sulfur dioxide", "density", "pH", "sulphates", "alcohol"]
-
现在训练数据已经准备好了,我们可以创建 H2O AutoML 对象并开始模型训练。以下脚本执行此操作:
aml_for_color_predictor = H2OAutoML(max_models=10, seed=123, exclude_algos=["StackedEnsemble"], max_runtime_secs=300) aml_for_color_predictor.train(x = features, y = label, training_frame=train, validation_frame = valid)
当初始化 H2OautoML
对象时,我们使用 StackedEnsemble
值设置 exclude_algos
参数。这样做是因为堆叠集成模型不支持 POJO,正如我们在 第十章,与普通旧 Java 对象 (POJOs) 一起工作 中所学到的。
这启动了 AutoML 模型训练过程。一些 print
语句将帮助你观察模型训练过程的进度和结果。
-
模型训练过程完成后,脚本将检索主模型并将其作为具有正确名称的 POJO(即
WineColorPredictor
)下载,并将其放置在tmp
目录中:model = aml_for_color_predictor.leader model.model_id = "WineColorPredictor" print(model) model.download_pojo(path="tmp")
-
接下来,脚本将对下一个模型(即回归模型)做同样的事情,以预测葡萄酒的质量。它稍微调整了标签并将其设置为
quality
。其余步骤相同:label="quality" aml_for_quality_predictor = H2OAutoML(max_models=10, seed=123, exclude_algos=["StackedEnsemble"], max_runtime_secs=300) aml_for_quality_predictor.train(x = features, y = label, training_frame=train, validation_frame = valid)
-
训练完成后,脚本将提取主模型,将其命名为
WineQualityPredictor
,并将其作为 POJO 下载到tmp
目录中:model = aml_for_color_predictor.leader model.model_id = "WineQualityPredictor" print(model) model.download_pojo(path="tmp")
-
现在我们已经下载了两个模型 POJO,我们需要将它们移动到
src/main/java/com.h2o_wine_predictor.demo/model/
目录。但在我们这样做之前,我们还需要将 POJO 添加到com.h2o.wine_predictor.demo
包中,以便PredictionService.java
文件可以导入模型。因此,脚本通过创建一个新文件,将包包含指令行添加到文件中,附加原始 POJO 文件的其余部分,并将文件保存在src/main/java/com.h2o_wine_predictor.demo/model/
目录中来实现这一点:with open("tmp/WineColorPredictor.java", "r") as raw_model_POJO: with open("src/main/java/com.h2o_wine_predictor.demo/model/ WineColorPredictor.java", "w") as model_POJO: model_POJO.write(f'package com.h2o_wine_predictor.demo;\n' + raw_model_POJO.read())
-
它对
WineQualityPredictor
模型也做了同样的事情:with open("tmp/WineQualityPredictor.java", "r") as raw_model_POJO: with open("src/main/java/com.h2o_wine_predictor.demo/model/ WineQualityPredictor.java", "w") as model_POJO: model_POJO.write(f'package com.h2o_wine_predictor.demo;\n' + raw_model_POJO.read())
-
最后,它删除
tmp
目录以清理所有内容:shutil.rmtree("tmp")
因此,让我们运行这个脚本并生成我们的模型。你可以在你的终端中执行以下命令来做到这一点:
python3 script.py
这应该在 src/main/java/com.h2o_wine_predictor.demo/model/
目录中生成相应的模型 POJO 文件。
现在,让我们观察位于 src/main/java/com.h2o_wine_predictor.demo/service
目录下的 PredictionService
文件。
PredictionService
文件中的 PredictionService
类具有以下属性:
-
wineColorPredictorModel
: 这是一个EasyPredictModelWrapper
类型的属性。它是由PredictionService
文件导入的 h2o-genmodel 库中的类。我们使用此属性来加载我们刚刚使用script.py
生成的WineColorPredictor
模型。我们将使用此属性来对后续的请求进行预测。 -
wineQualityPredictorModel
: 与wineColorPredictorModel
类似,这是使用相同EasyPredictModelWrapper
的葡萄酒质量等效属性。此属性将用于加载WineQualityPredictor
模型,并使用它来预测葡萄酒的质量。
现在我们已经了解了这个文件的属性,让我们来看看方法,具体如下:
-
createJsonResponse()
: 这个函数在意义上相当直接,它从WineColorPredictor
模型的二项分类预测结果和WineQualityPredictor
模型的回归预测结果中获取,并将它们合并成一个 JSON 响应,该响应由网络应用程序发送回客户端。 -
predictColor()
: 这个函数使用PredictionService
类的wineColorPredictorModel
属性对数据进行预测。它以BinomialModelPrediction
对象的形式输出葡萄酒颜色的预测结果,这是 h2o-genmodel 库的一部分。 -
predictQuality()
: 这个函数使用PredictionService
类的wineQualityPredictorModel
属性对数据进行预测。它以RegressionModelPrediction
对象的形式输出葡萄酒质量的预测结果,这是 h2o-genmodel 库的一部分。 -
fillRowDataFromHttpRequest()
: 这个函数负责将来自 POST 请求的特征值转换为RowData
对象,该对象将被传递给wineQualityPredictorModel
和wineColorPredictorModel
以进行预测。RowData
是 h2o-genmodel 库中的一个对象。 -
getPrediction()
: 这个函数由PredictionController
调用,它将特征值作为映射传递以进行预测。此函数内部调用所有之前提到的函数,并协调整个预测过程:
-
它从 POST 请求中获取特征值作为输入。它将这些值(以
Map
对象的形式)传递给fillRowDataFromHttpRequest()
,该函数将它们转换为RowData
类型。 -
然后,它将此
RowData
传递给predictColor()
和predictQuality()
函数以获取预测值。 -
然后,它将这些结果传递给
createJsonResponse()
函数,以创建包含预测值的适当 JSON 响应,并将 JSON 返回给PredictionController
,控制器将其返回给客户端。
现在我们已经有机会了解整个项目的重要部分,让我们继续运行应用程序,以便我们可以在本地机器上运行 Web 服务。然后,我们将使用葡萄酒质量特征值运行一个简单的 cURL
命令,看看我们是否得到响应。
要启动应用程序,你可以执行以下操作:
-
如果你使用 IntelliJ IDE,则可以直接点击 IDE 右上角的绿色播放按钮。
-
或者,你可以在项目目录中直接运行它,该目录包含
pom.xml
文件,并执行以下命令:mvn spring-boot:run -e
如果一切正常,你应该得到以下类似的输出:
图 13.4 – 成功的 Spring Boot 应用程序运行输出
现在,Spring Boot 应用程序正在运行,剩下的事情就是通过向运行在 localhost:8082
的 Web 服务发出 POST 请求调用来测试它。
打开另一个终端,并执行以下 curl
命令以发出预测请求:
curl -X POST localhost:8082/api/v1/predict -H "Content-Type: application/json" -d '{"fixed acidity":6.8,"volatile acidity":0.18,"citric acid":0.37,"residual sugar":1.6,"chlorides":0.055,"free sulfur dioxide":47,"total sulfur dioxide":154,"density":0.9934,"pH":3.08," ,"sulphates":0.45,"alcohol":9.1}'
请求应发送到 Web 应用程序,应用程序将提取特征值,将它们转换为 RowData
对象类型,将 RowData
传递给预测函数,获取预测结果,将预测结果转换为适当的 JSON
,并将 JSON
作为响应返回。这应该看起来如下所示:
图 13.5 – Spring Boot 网络应用程序的预测结果
从 JSON 响应中,你可以看到预测的葡萄酒颜色是 white
,其质量是 5.32
。
恭喜!你已经在 Spring Boot 网络应用程序上实现了一个机器学习预测服务。你可以通过添加一个前端来进一步扩展此服务,该前端接受特征值作为输入,并添加一个按钮,点击该按钮将创建所有这些值的 POST 主体,并将 API 请求发送到后端。请随意实验这个项目,因为你可以有很多方法在 Web 服务中使用 H2O 模型 POJO。
在下一节中,我们将学习如何使用 H2O AutoML 和另一个有趣的技术 Apache Storm 进行实时预测。
使用 H2O AutoML 和 Apache Storm
Apache Storm 是一个开源的数据分析和计算工具,用于实时处理大量流数据。在现实世界中,你经常会遇到许多系统持续生成大量数据。你可能需要对这些数据进行一些计算或运行一些过程,以便在实时生成时提取有用信息。
Apache Storm 是什么?
让我们以一个在非常繁忙的 Web 服务中使用的 日志系统 为例。假设这个 Web 服务每秒接收数百万个请求,它将生成大量的日志。您已经有一个系统来存储这些日志到您的数据库中。现在,这些日志数据最终会堆积起来,您将在数据库中存储数以 PB 计的日志数据。一次性查询所有这些历史数据来处理它将非常慢且耗时。
您可以做到的是在数据生成时处理数据。这正是 Apache Storm 发挥作用的地方。您可以将您的 Apache Storm 应用程序配置为执行所需的处理,并将您的日志数据引导通过它,然后存储到您的数据库中。这将简化处理过程,使其成为实时处理。
Apache Storm 可用于多种用例,例如实时分析、数据管道中的 提取-转换-加载(ETL)数据,甚至机器学习(ML)。使 Apache Storm 成为实时处理首选解决方案的原因在于它的速度之快。Apache 基金会进行的一项基准测试发现,Apache Storm 每个节点每秒可以处理大约一百万个元组。Apache Storm 还非常可扩展和容错,这保证了它将处理所有传入的实时数据。
因此,让我们深入探讨 Apache Storm 的架构,以了解它是如何工作的。
理解 Apache Storm 的架构
Apache Storm 使用集群计算,类似于 Hadoop 和 H2O 的工作方式。考虑以下 Apache Storm 的架构图:
图 13.6 – Apache Storm 架构
Apache Storm 将其集群中的节点分为两类 – 主节点和工节点。这些节点的特性如下:
-
主节点:主节点运行一个名为 Nimbus 的特殊守护进程。Nimbus 守护进程负责在集群中的所有工节点之间分配数据。它还监控故障,并在检测到故障后重新发送数据到其他节点,确保没有数据被遗漏处理。
-
工节点:工节点运行一个名为 Supervisor 的守护进程。Supervisor 守护进程是始终监听工作并根据计算需要启动或停止底层进程的服务。
主节点和工节点之间使用各自的守护进程进行通信,这是通过 Zookeeper 集群 实现的。简而言之,Zookeeper 集群是一个集中式服务,为无状态组维护配置和同步服务。在这种情况下,主节点和工节点是无状态且快速失败的服务。所有状态细节都存储在 Zookeeper 集群中。这很有益,因为保持节点无状态有助于容错,因为节点可以被恢复并开始工作,就像什么都没发生过一样。
小贴士
如果你感兴趣,想了解 Zookeeper 的各种概念和技术细节,那么请自由地在其官网zookeeper.apache.org/
上详细探索。
在我们继续 Apache Storm 的实现部分之前,我们需要了解某些重要概念,这些概念对于理解 Apache Storm 的工作方式至关重要。不同的概念如下:
-
元组(Tuples):Apache Storm 使用一个称为元组的数据模型作为其要处理的主要数据单元。它是一个命名值列表,可以是任何类型的对象。Apache Storm 支持所有原始数据类型。但它也可以支持自定义对象,这些对象可以被反序列化为原始类型。
-
流(Streams):流是无界元组的序列。流表示你的数据从一处流向下一处转换的路径。Apache Storm 提供的基本原语用于执行这些转换是喷泉和螺栓:
-
喷泉(Spouts):喷泉是流的来源。它是流的起点,从这里读取来自外部世界的数据。它从外部世界获取这些数据并将其发送到螺栓。
-
螺栓(Bolt):螺栓是一个从单个或多个流中消耗数据、对其进行转换或处理,然后输出结果的过程。你可以在连续的流中链接多个螺栓,将一个螺栓的输出作为下一个螺栓的输入,以执行复杂的处理。螺栓可以运行函数、过滤数据、执行聚合,甚至可以将数据存储在数据库中。你可以在螺栓上执行任何你想要的功能。
-
-
拓扑(Topologies):使用流、喷泉和螺栓以有向无环图(DAG)的形式实时处理数据的整个编排过程称为拓扑。你需要使用 Apache Storm 的主函数将此拓扑提交给 Nimbus 守护进程。拓扑图包含节点和边,就像常规的图结构一样。每个节点包含处理逻辑,每条边显示数据如何在两个节点之间传输。Nimbus 和拓扑都是Apache Thrift结构,这是一种特殊的类型系统,允许程序员在任何编程语言中使用本地类型。
提示
你可以通过访问thrift.apache.org/docs/types
来了解更多关于 Apache Thrift 的信息。
现在你已经更好地理解了 Apache Storm 是什么以及其实施中涉及的各种概念,我们可以继续本节的实现部分,从安装 Apache Storm 开始。
提示
Apache Storm 是一个非常强大且复杂的系统。它不仅在机器学习之外有广泛的应用,而且还有许多特性和支持。如果你想了解更多关于 Apache Storm 的信息,请访问storm.apache.org/
。
安装 Apache Storm
让我们先记下安装 Apache Storm 的基本要求。它们如下:
-
Java 版本大于 Java 8
-
最新的 Maven 版本,最好是 3.8.6 版
因此,请确保这些基本要求已经安装到您的系统上。现在,让我们先下载 Apache Storm 仓库。您可以在 github.com/apache/storm
找到该仓库。
因此,执行以下命令以将存储库克隆到您的系统:
git clone https://github.com/apache/storm.git
下载完成后,您可以打开 storm
文件夹,一窥其内容。您会注意到有很多文件,所以在试图弄清楚从哪里开始时可能会感到不知所措。别担心——我们将通过非常简单的示例来工作,这些示例应该足以让您对 Apache Storm 的工作方式有一个基本的了解。然后,您可以从那里分支出去,以更好地了解 Apache Storm 提供的内容。
现在,打开您的终端并导航到克隆的仓库。在您开始实现任何 Apache Storm 功能之前,您需要本地构建 Apache Storm 本身。您需要这样做,因为本地构建 Apache Storm 会生成重要的 JAR 文件,这些文件将被安装到您的 $HOME/.m2/repository
文件夹中。这是 Maven 在构建您的 Apache Storm 应用程序时将检索 JAR 依赖项的文件夹。
因此,在仓库根目录下执行以下命令以本地构建 Apache Storm:
mvn clean install -DskipTests=true
构建可能需要一些时间,因为 Maven 将构建几个对您的应用程序重要的 JAR 文件。所以,当这个过程中发生时,让我们了解我们将要工作的问题描述。
理解问题描述
假设您在一家医疗公司工作。医疗官员有一个要求,他们希望创建一个系统,预测一个人在心脏病发作后是否可能遭受任何并发症,或者他们是否可以安全出院。难点在于这个预测服务将用于全国的所有医院,他们需要立即的预测结果,以便医生可以决定是否将患者留院观察几天以监测他们的健康状况,或者决定让他们出院。
因此,机器学习问题在于将会有数据流进入我们的系统,系统需要立即做出预测。我们可以设置一个 Apache Storm 应用程序,将所有数据流输入到预测服务中,并部署使用 H2O AutoML 训练的模型 POJO 来进行预测。
我们可以在心脏衰竭临床数据集上训练模型,该数据集可在 archive.ics.uci.edu/ml/datasets/Heart+failure+clinical+records
找到。
以下截图显示了数据集的一些示例内容:
图 13.7 – 心脏衰竭临床数据集
此数据集包含以下特征:
-
年龄:此功能表示患者的年龄,单位为年
-
1
表示是,0
表示否 -
1
表示是,0
表示否 -
肌酸激酶:此功能表示血液中 CPK 酶的水平,单位为每升微克(mcg/L)
-
1
表示是,0
表示否 -
射血分数:此功能表示每次收缩时心脏排出的血液百分比
-
血小板:此功能表示血液中的血小板,单位为每毫升千血小板(ml)
-
1
表示患者为女性,0
表示患者为男性 -
血清肌酐:此功能表示血液中血清肌酐的水平,单位为每毫升毫克(mg/dL)
-
血清钠:此功能表示血液中血清钠的水平,单位为每升毫当量(mEq/L)
-
1
表示是,0
表示否 -
时间:此功能表示随访天数
-
1
表示是,0
表示否
现在我们已经了解了问题陈述以及我们将要处理的数据集,让我们设计如何使用 Apache Storm 和 H2O AutoML 解决这个问题的架构。
设计架构
让我们看看所有技术如何协同工作的整体架构。参考以下心脏衰竭并发症预测服务架构图:
图 13.8 – 使用 H2O AutoML 与 Apache Storm 的架构图
让我们了解架构的各个组成部分:
-
script.py
:从架构角度来看,解决方案相当简单。首先,我们使用 H2O AutoML 训练模型,这可以通过使用此脚本轻松完成,该脚本导入数据集,设置标签和特征,并运行 AutoML。然后可以提取领先模型作为 POJO,我们可以在 Apache Storm 中使用它进行预测。 -
数据喷泉:在 Apache Storm 中,我们将有一个喷泉,它将不断读取数据并将其实时传递给预测螺栓。
-
预测螺栓:此螺栓包含预测服务,它导入训练好的模型 POJO 并使用它进行预测。
-
分类螺栓:预测螺栓的结果传递给此螺栓。此螺栓根据预测螺栓的二分类结果将结果分类为潜在并发症和无并发症。
现在我们已经设计了一个简单且良好的解决方案,让我们继续其实现。
在实现上工作
此服务已在 GitHub 上提供。代码库可以在github.com/PacktPublishing/Practical-Automated-Machine-Learning-on-H2O/tree/main/Chapter%2013/h2o_apache_storm/h2o_storm
找到。
因此,下载仓库并导航到/Chapter 13/h2o_apache_storm/h2o_storm/
。
你会看到我们有两个文件夹。一个是storm-starter
目录,另一个是storm-streaming
目录。让我们首先关注storm-streaming
目录。启动你的 IDE 并打开storm-streaming
项目。一旦打开项目,你应该会看到一个类似于以下目录结构:
图 13.9 – storm_streaming 目录结构
此目录结构包含以下重要文件:
-
scripty.py
:这是我们将在心脏衰竭并发症数据集上训练模型的 Python 脚本。脚本启动 H2O 服务器实例,导入数据集,然后运行 AutoML 来训练模型。我们将在稍后详细探讨这一点。 -
H2ODataSpout.java
:这是一个 Java 文件,其中包含 Apache Storm spout 及其功能。它从live_data.csv
文件中读取数据,并将单个观测值逐个转发到 bolt,模拟数据的实时流动。 -
H2OStormStarter.java
:这是一个 Java 文件,其中包含 Apache Storm 拓扑以及两个 bolt 类 – 预测 bolt 和分类 bolt。我们将使用此文件启动我们的 Apache Storm 服务。 -
training_data.csv
:这是我们用来训练模型的包含部分心脏衰竭并发症数据的数据集。 -
live_data.csv
:这是我们用来模拟 Apache Storm 应用程序实时数据流入的心脏衰竭并发症数据集。
与之前在单独的应用程序仓库中做更改的实验不同,对于这次实验,我们将在 Apache Storm 的仓库中做更改。
以下步骤已在Ubuntu 22.04 LTS上执行;IntelliJ IDEA 版本 2022.1.4已被用作 IDE。请随意使用任何支持 Maven 框架的 IDE,以获得更好的支持。
让我们先了解模型训练脚本script.py
。script.py
的代码如下:
-
首先,脚本导入依赖项:
import h2o from h2o.automl import H2OautoML
-
导入完成后,H2O 服务器被初始化:
h2o.init()
-
一旦 H2O 服务器启动并运行,脚本将导入
training_data.csv
文件:wine_quality_dataframe = h2o.import_file(path = "training_data.csv")
-
现在 DataFrame 已经导入,我们可以开始使用 AutoML 对模型进行训练过程。因此,脚本设置了标签和特征,如下所示:
label = "complications" features = ["age", "anemia", "creatinine_phosphokinase", "diabetes", "ejection_fraction", "high_blood_pressure", "platelets", "serum_creatinine ", "serum_sodium", "sex", "smoking", "time"]
-
现在,我们可以创建 H2O AutoML 对象并开始模型训练:
aml_for_complications = H2OAutoML(max_models=10, seed=123, exclude_algos=["StackedEnsemble"], max_runtime_secs=300) aml_for_complications.train(x = features, y = label, training_frame = wine_quality_dataframe )
由于 POJO 不支持堆叠集成模型,我们使用StackedEnsemble
值设置exclude_algos
参数。
这启动了 AutoML 模型训练过程。这里有一些print
语句,它们将帮助您观察模型训练过程的进度和结果。
-
一旦模型训练过程完成,脚本检索主模型,并以正确的名称(即
HeartFailureComplications
)将其作为 POJO 下载,并将其放置在tmp
目录中:model = aml_for_color_predictor.leader model.model_id = "HeartFailureComplications" print(model) model.download_pojo(path="tmp")
因此,让我们运行这个脚本并生成我们的模型。在您的终端中执行以下命令:
python3 script.py
这应该在tmp
目录中生成相应的模型 POJO 文件。
现在,让我们调查仓库中的下一个文件:H2ODataSpout.java
。Java 文件中的H2ODataSpout
类有几个属性和函数,对于构建 Apache Storm 应用程序非常重要。我们不会过多关注它们,但让我们看看在应用程序的业务逻辑中扮演更大角色的函数。它们如下:
-
nextTuple()
: 这个函数包含从live_data.csv
文件读取数据的逻辑,并将数据行行地发送到 Prediction Bolt。让我们快速看一下代码:- 首先,你有睡眠计时器。众所周知,Apache Storm 是一个超级快速的现实数据处理系统。观察我们的实时数据通过系统对我们来说将是困难的,所以
sleep
函数确保有 1,000 毫秒的延迟,这样我们就可以轻松观察数据的流动并看到结果:
Util.sleep(1000)
- 首先,你有睡眠计时器。众所周知,Apache Storm 是一个超级快速的现实数据处理系统。观察我们的实时数据通过系统对我们来说将是困难的,所以
- 然后该函数将
live_data.csv
文件实例化到程序中:
File file = new File("live_data.csv")
- 然后代码声明了
observation
变量。这仅仅是将被读取并存储在这个变量中的单个行数据,由 spout 读取:
String[] observation = null;
- 然后,我们有逻辑,其中 spout 程序读取数据中的行。读取哪一行是由
_cnt
原子整数决定的,它在 spout 读取并将行发送到 Prediction Bolt 的无限循环中时递增。这个无限循环模拟了数据的连续流动,尽管live_data.csv
只包含有限的数据:
try {
String line="";
BufferedReader br = new BufferedReader(new FileReader(file));
while (i++<=_cnt.get()) line = br.readLine(); // stream thru to next line
observation = line.split(",");
} catch (Exception e) {
e.printStackTrace();
_cnt.set(0);
}
- 然后,我们有原子数递增,以便下一次迭代可以获取数据中的下一行:
_cnt.getAndIncrement();
if (_cnt.get() == 1000) _cnt.set(0);
- 最后,我们有
_collector.emit()
函数,它发出行数据,以便将其存储在_collector
中,然后_collector
被 Prediction Bolt 消费:
_collector.emit(new Values(observation));
-
declareOutputFields()
: 在这个方法中,我们声明了我们的数据头。我们可以使用训练好的 AutoML 模型 POJO 的NAMES
属性来提取和使用这些头:LinkedList<String> fields_list = new LinkedList<String>(Arrays.asList(ComplicationPredictorModel.NAMES)); fields_list.add(0,"complication"); String[] fields = fields_list.toArray(new String[fields_list.size()]); declarer.declare(new Fields(fields));
-
其他杂项函数:剩余的
open()
、close()
、ack()
、fail()
和getComponentConfiguration()
函数是用于错误处理和预处理或后处理活动的辅助函数。为了使这个实验简单,我们不会过多地探讨它们。
接下来,让我们调查H2OStormStarter.java
文件。此文件包含执行预测和分类所需的两个 bolt,以及构建 Apache Storm 拓扑并将其传递给 Apache Storm 集群的h2o_storm()
函数。让我们深入了解各个属性:
-
class PredictionBolt
:这是一个Bolt
类,负责获取心脏衰竭并发症数据集的类别概率。它导入 H2O 模型 POJO 并使用它来计算传入行数据的类别概率。它有三个函数 –prepare()
、execute()
和declareOutputFields()
。我们只关注execute
函数,因为它包含 bolt 的执行逻辑;其余的都是辅助函数。execute
函数包含以下代码:- 此函数首先执行的操作是导入 H2O 模型 POJO:
HeartFailureComplications h2oModel = new HeartFailureComplications();
- 然后,它从其参数变量中提取输入元组值并将它们存储在
raw_data
变量中:
ArrayList<String> stringData = new ArrayList<String>();
for (Object tuple_value : tuple.getValues()) stringData.add((String) tuple_value);
String[] rawData = stringData.toArray(new String[stringData.size()]);
- 接下来,代码将行中的所有分类数据分类映射:
double data[] = new double[rawData.length-1];
String[] columnName = tuple.getFields().toList().toArray(new String[tuple.size()]);
for (int I = 1; i < rawData.length; ++i) {
data[i-1] = h2oModel.getDomainValues(columnName[i]) == null
? Double.valueOf(rawData[i])
: h2oModel.mapEnum(h2oModel.getColIdx(columnName[i]), rawData[i]);
}
- 然后,代码获取预测并发出结果:
double[] predictions = new double [h2oModel.nclasses()+1];
h2oModel.score0(data, predictions);
_collector.emit(tuple, new Values(rawData[0], predictions[1]));
- 最后,代码确认了元组,以便 spout 知道其消费情况,不会为重试重新发送元组:
_collector.ack(tuple);
-
Bolt
类也有一些辅助函数,以及主要的execute()
函数。让我们深入了解这个函数,以了解函数中发生了什么:-
函数简单地根据
_threshold
值计算是否存在可能的并发症或无并发症的可能性,并将结果发送回去:_collector.emit(tuple, new Values(expected, complicationProb <= _threshold ? "No Complication" : "Possible Complication")); _collector.ack(tuple);
-
-
h2o_storm()
:这是应用程序的主要函数,使用H2ODataSpout
和两个 bolt(预测 bolt 和分类 bolt)构建拓扑。让我们深入了解其功能。- 首先,函数实例化
TopologyBuilder()
:
TopologyBuilder builder = new TopologyBuilder();
- 首先,函数实例化
- 使用此对象,它通过设置 spout 和 bolt 来构建拓扑,如下所示:
builder.setSpout("inputDataRow", new H2ODataSpout(), 10);
builder.setBolt("scoreProbabilities", new PredictionBolt(), 3).shuffleGrouping("inputDataRow");
builder.setBolt("classifyResults", new ClassifierBolt(), 3).shuffleGrouping("scoreProbabilities");
- Apache Storm 也需要一些配置数据来设置其集群。由于我们正在创建一个简单的示例,我们可以直接使用默认配置,如下所示:
Config conf = new Config();
- 最后,它创建一个集群并提交它创建的拓扑以及配置:
LocalCluster cluster = new LocalCluster();
cluster.submitTopology("HeartComplicationPredictor", conf, builder.createTopology());
- 之后,有一些函数将整个实验封装在一起。
Util.sleep()
函数用于暂停一小时,以便 Apache Storm 可以无限循环功能,同时模拟实时数据的连续流动。cluster.killTopology()
函数终止HeartComplicationPredictor
拓扑,停止集群中的模拟。最后,cluster.shutdown()
函数关闭 Apache Storm 集群,释放资源:
Utils.sleep(1000 * 60 * 60);
cluster.killTopology("HeartComplicationPredictor");
cluster.shutdown();
现在我们已经更好地理解了文件的内容以及我们将如何运行我们的服务,让我们继续并查看storm-starter
项目的目录结构。结构如下:
图 13.10 – storm-starter 目录结构
src
目录包含几种不同类型的 Apache Storm 拓扑示例,你可以选择进行实验。我强烈建议你这样做,因为这将帮助你更好地理解 Apache Storm 在配置不同需求的流服务时的多功能性。
然而,我们将在这个 test
目录中执行这个实验,以保持我们的文件与 src
目录中的文件隔离。那么,让我们看看我们如何运行这个实验。
按照以下步骤构建和运行实验:
-
在
storm-streaming
目录中,运行script.py
文件以生成 H2O 模型 POJO。脚本应该运行 H2O AutoML 并生成一个排行榜。领先模型将被提取,重命名为HeartFailureComplications
,并作为 POJO 下载。在你的终端中运行以下命令:python3 script.py
-
HeartFailureComplications
POJO 将被storm-starter
项目的其他文件导入,因此为了确保它可以被同一包中的文件正确导入,我们需要将这个 POJO 添加到同一个包中。因此,修改 POJO 文件,将storm.starter
包作为第一行添加。 -
现在,将
HeartFailureComplications
POJO 文件、H2ODataSpout.java
文件和H2OStormStarted.java
文件移动到storm-starter
仓库内的storm-starter/test/jvm/org.apache.storm.starter
目录中。 -
接下来,我们需要将
h2o-model.jar
文件导入到storm-starter
项目中。我们可以通过在实验的pom.xml
文件中添加以下依赖项来实现,如下所示:<dependency> <groupId>ai.h2o</groupId> <artifactId>h2o-genmodel</artifactId> <version>3.36.1.3</version> </dependency>
你的目录现在应该看起来如下所示:
图 13.11 – 文件传输后的 storm-starter 目录结构
- 最后,我们将通过右键单击
H2OStormStarter.java
文件并运行它来运行此项目。你应该会得到一个显示你的 spout 和 bolt 作用的恒定输出流。这可以在以下屏幕截图中看到:
图 13.12 – Apache Storm 中的心脏并发症预测输出
如果你仔细观察结果,你应该会看到日志中有执行者;所有的 Apache Storm spouts 和 bolts 都是运行在集群内部的内部执行进程。你还会看到每个元组旁边的预测概率。这应该看起来如下所示:
图 13.13 – 心脏并发症预测结果
恭喜 – 我们刚刚覆盖了另一个设计模式,它展示了我们如何使用 H2O AutoML 训练的模型,通过 Apache Storm 对流数据进行实时预测。这标志着本章最后一个实验的结束。
摘要
在本章中,我们关注了如何使用不同的技术在不同场景下实现使用 H2O AutoML 训练的模型,以便对各种数据进行预测。
我们从一个场景开始,在这个场景中,我们尝试在 Web 服务上对数据进行预测,并实现了 AutoML 领导者模型。我们创建了一个简单的 Web 服务,该服务使用 Spring Boot 和 Apache Tomcat Web 服务器在本地主机上托管。我们使用 AutoML 在数据上训练模型,提取领导者模型作为 POJO,并将该 POJO 作为类加载到 Web 应用程序中。通过这样做,应用程序能够使用模型对作为 POST 请求接收到的数据进行预测,并返回预测结果。
然后,我们探讨了另一种设计模式,我们的目标是预测实时数据。我们必须实现一个能够模拟实时数据流的系统。我们使用 Apache Storm 做到了这一点。首先,我们深入了解了 Apache Storm 是什么,它的架构以及它是如何通过使用 spouts 和 bolts 来工作的。利用这些知识,我们构建了一个实时数据流应用程序。我们将 AutoML 训练的模型部署在预测 Bolt 中,Apache Storm 应用程序能够使用该模型对实时流数据进行预测。
这本书的最后一章到此结束。在使用 H2O AutoML 的过程中,我们还可以利用无数的特征、概念和设计模式。你越是对这项技术进行实验,你将越擅长实现它。因此,强烈建议你继续实验这项技术,并在自动化你的机器学习工作流程的同时,发现解决机器学习问题的新方法。