news 2026/3/26 23:21:27

MLOps – 使用 PyTest 进行数据验证

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MLOps – 使用 PyTest 进行数据验证

原文:towardsdatascience.com/mlops-data-validation-with-pytest-749641874871

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/c267aeb3de57e3d15c5a80e2647dc529.png

照片由 Michael Dziedzic 在 Unsplash 提供

简介

在一个我们试图尽可能自动化的 MLOps 流程中,考虑到最小化程序员直接干预可能引起的错误数量的目标,对数据集进行验证也很重要。我认为每个人都熟悉机器学习的第 1 规则:垃圾输入,垃圾输出。我们开发的模型多么复杂,如果数据集没有得到妥善处理,我们很可能得到不良的结果。

在这篇文章中,我们将看到如何使用 PyTest 对数据集进行自动验证。

我使用 Deepnote 运行这篇文章的脚本:这是一个非常适合协作数据科学项目和原型设计的基于云的笔记本。

关于 ETL

对于第一次接触机器学习的人来说,他们通常必须解决在 Kaggle 上找到的挑战类型。在这些挑战中,我们几乎总是有一个静态的数据集,这个数据集在时间上不会改变。然而,这在现实世界中并不完全正确。

当在真实的机器学习产品上工作时,数据可能会持续变化。得到的结果数据是通过数据提取、数据转换和数据加载的初步步骤获得的。

这三个阶段通常用缩写 ETL 来概括。简单来说,想象你需要进行数据收集,以便有足够的数据进行模型训练。你将需要从某处提取数据,例如通过抓取,或者分析开源数据能为你做什么(提取)。

数据可能以不同的格式出现,也许我们已经收集了一些 CSV 文件、JSON 文件以及一些 txt 文件。因此,我们必须处理这些数据的转换,以实现一致性。

最后,我们需要使这些数据对正在工作的数据科学家来说易于使用。因此,我们可以将其上传到易于下载的系统(例如 Hugging Face, AWS)。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/d1cea28e2b638bc21405f63e409bfbb8.png

ETL(图片由作者提供)

在这篇文章中,你可以了解一些 ETL 的最佳实践。

可能会出什么问题?

既然我们已经知道了数据的收集方式,那么让我们来了解数据科学家为什么需要处理数据验证以及如何处理数据验证。在我们的数据集中可能会出现几个问题。

  1. 我们周围的世界是动态变化的,因此数据分布也会发生变化。想象一个预测某些 T 恤价格的模型。XXL 尺寸的预测价格非常低,因为没有人购买它们。但我们知道,随着时间的推移,人们会越来越高,所以将来可能需要重新训练一个更加重视大号的模型。

  2. 源数据中发生了我们没有报告的变化。负责 ETL 管道的团队更改了关于电影评分系统的数据,从一星到五星的系统转变为十星系统。

  3. 在 ETL 过程中数据摄入时出现了一个错误。可能有一个度量变化,我们从一个以厘米为单位表示的数据转变为以千米为单位表示的数据。

数据验证可以在数据分割(将数据分为训练集和测试集)之前或之后进行。不清楚在哪里进行最好,两种方法都有其优缺点。

PyTest 简介

PyTest 是一个广泛使用的 Python 库,用于运行各种测试。通常,我们在代码库中创建一个名为tests的文件夹,并在其中收集我们想要运行的几个测试的所有文件。每个文件将被命名为 _testxx.py。例如,我们可以有 _testdata.py或 _testmodel.py

tests|--test_data.py|--test_model.py

执行测试的主要 Python 命令是assert。此命令确保满足某个条件,否则会返回错误。错误可以在条件之后定义为一个字符串。让我们看看一个例子。

cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fembed.deepnote.com%2F310235f2-1ad7-4694-9d0f-c991c1bf207f%2F3f615e10c25b470aba275a421c3adbe9%2F028a56b33b93490785c4e7c92e9abbbf%3Fheight%3D226.390625&display_name=Deepnote&url=https%3A%2F%2Fembed.deepnote.com%2F310235f2-1ad7-4694-9d0f-c991c1bf207f%2F3f615e10c25b470aba275a421c3adbe9%2F028a56b33b93490785c4e7c92e9abbbf%3Fheight%3D226.390625&image=https%3A%2F%2Fdeepnote.com%2Fstatic%2Fthumbnails%2Fmain.png&key=a19fcc184b9711e1b4764040d3dc5c07&type=text%2Fhtml&schema=deepnote

PyTest 将启动文件中检测到的所有测试函数,并确保所有断言都返回 True。如果它们没有,终端将显示哪些测试失败。以下是一个测试函数的示例。

cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fembed.deepnote.com%2F310235f2-1ad7-4694-9d0f-c991c1bf207f%2F3f615e10c25b470aba275a421c3adbe9%2F9f67be40bcee41d8a0794bc1b3abc452%3Fheight%3D173&display_name=Deepnote&url=https%3A%2F%2Fembed.deepnote.com%2F310235f2-1ad7-4694-9d0f-c991c1bf207f%2F3f615e10c25b470aba275a421c3adbe9%2F9f67be40bcee41d8a0794bc1b3abc452%3Fheight%3D173&image=https%3A%2F%2Fdeepnote.com%2Fstatic%2Fthumbnails%2Fmain.png&key=a19fcc184b9711e1b4764040d3dc5c07&type=text%2Fhtml&schema=deepnote

第一个问题就出现在这里。在前面的函数中,给定输入的值是什么?我们在测试阶段如何指定这样的变量?我们得到了 fixtures 的帮助!

PyTest 中的 fixtures

在许多情况下(如上面提到的例子)测试需要输入数据(例如数据)来做出断言。这些输入数据可以使用 PyTest 的 fixtures 提供。使用 fixtures,我们可以在测试中声明变量,而无需再进行赋值。然而,定义 fixtures 的函数必须与测试函数的输入变量具有相同的名称。让我们来看一个例子。

Deepnote

你在上面的代码块中可以看到,我们实现了一个名为 data(以函数命名)的装置,它返回一个名为df的数据框作为输出。因此,在 test_data_lenght 测试中,输入数据将采用装置的值,因此将与df数据框相匹配。

对于一个固定装置,我们可以指定其作用域,这样我们就可以决定何时销毁该装置。例如,如果作用域是“会话”,则相同的装置将在整个会话中存在,这样第一个测试就可以更改数据值,然后将其传递给第二个测试。

如果我们使用“function”作用域,每个测试都将使用一个新鲜且未更改的装置副本作为输入。

在 PyTest 文档中,你可以了解所有不同类型的范围。

装置是在测试首次请求时创建的,并且根据它们的scope来销毁:

function:默认作用域,装置在测试结束时销毁。

class:在类的最后一个测试的拆卸过程中销毁装置。

module:在模块的最后一个测试的拆卸过程中销毁装置。

package:在包的最后一个测试的拆卸过程中销毁装置。

session:装置在测试会话结束时销毁。

为机器学习数据集编写测试可能比为传统软件工程编写测试更复杂。在传统软件中,我们通常对每个函数都有一个预期的输出,所以如果测试返回的结果与我们预期的不同,显然存在错误。

另一方面,在数据集中,这更为复杂,因为我们不确定会期望什么。例如,我们假设数据集中特征“高度”的平均值是 1.70 厘米。测试显示平均值为“1.75”。我们应该怎么办?这是错误吗?或者我们在真正高的人的数据中添加了一些样本,从而提高了平均值?

因此,让我们先看看我们可以对数据集进行的简单确定性测试,然后再讨论非确定性测试。

确定性测试

编写确定性测试相当简单。数据集的确定性是什么?例如,必须精确为X的列数,或者必须 ≥N的行数,否则我们没有足够的数据。

对于分类变量,我们可以检查值是否在一个范围内。例如,如果特征 “颜色” 只能取[红色, 绿色, 蓝色]这些值,我们就可以进行这样的检查。

让我们看看这些类型测试的示例文件。

cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fembed.deepnote.com%2F310235f2-1ad7-4694-9d0f-c991c1bf207f%2F3f615e10c25b470aba275a421c3adbe9%2F970bb00ba134450eb3808bc9b9ff729c%3Fheight%3D1055&display_name=Deepnote&url=https%3A%2F%2Fembed.deepnote.com%2F310235f2-1ad7-4694-9d0f-c991c1bf207f%2F3f615e10c25b470aba275a421c3adbe9%2F970bb00ba134450eb3808bc9b9ff729c%3Fheight%3D1055&image=https%3A%2F%2Fdeepnote.com%2Fstatic%2Fthumbnails%2Fmain.png&key=a19fcc184b9711e1b4764040d3dc5c07&type=text%2Fhtml&schema=deepnote

在此代码中,我们找到了以下函数:

  • data: 固定装置,其中我们暴露包含数据框的变量

  • test_column_presence_and_type: 在这个函数中,我们确保数据集中存在四个列[年龄, 薪资, 姓名, 类型],并且它们的类型是正确的。

  • test_class_names: 这个函数确保类型值在已知的值中。它确保我们不会找到我们不期望的值。

  • test_column_ranges: 在这里,我们确保数值变量在一个特定的范围内。例如,年龄永远不能是负数!

非确定性测试

在非确定性测试中,我们希望测量考虑不确定性的值。每当谈到不确定性时,概率和统计学就会介入,我们也将在这里使用它们。

一种常见的做法是通过与之前的版本进行比较来评估我们目前正在处理的数据集的值。

我们可以在数据集上进行的检查示例包括:

  • 检查异常值的存在

  • 检查一个或多个列的值分布

  • 检查一个或多个列之间,或者所有列与目标列(要预测的)之间是否存在相关性

  • 检查各个列的均值和标准差

如前所述,在非确定性测试中,通常使用统计数据,以过去的数据为例并与当前数据进行比较。因此,了解假设检验是如何工作的以及我们如何使用它来进行这些比较是非常重要的。

在本文中,我们将简要介绍假设检验的基本知识。如果您想深入了解,我建议您观看这个关于假设检验的视频:

cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FVK-rnA3-41c%3Ffeature%3Doembed&display_name=YouTube&url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DVK-rnA3-41c&image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FVK-rnA3-41c%2Fhqdefault.jpg&key=a19fcc184b9711e1b4764040d3dc5c07&type=text%2Fhtml&schema=youtube

当我们处理假设检验时,我们总是测试一个被称为零假设的假设与一个备择假设。

  • 零假设 (H_0):是科学界广泛接受的假设。在我们的情况下,它可能是对数据做出的假设。

  • 备择假设 (H_a):这是我想要被接受的假设,它与零假设不一致。显然,为了使我的新假设被接受,我必须提供数据来证实我的假设,这样就更容易说服大家我的新假设是正确的。

一个经典的例子是:

  • 零假设 (H_0):两个样本来自具有相同均值的正态分布的总体。

  • 备择假设:两个样本来自具有不同均值的正态分布的总体。

根据所做的假设,有各种统计检验可以使用。每个统计检验都与假设相关。因此,选择正确的检验非常重要。以下是关于选择正确的统计检验的文章。

在我们的例子中,我们将使用t 检验

我们需要做的是,从样本开始,使用一个已知的公式计算一个称为检验统计量的值。从检验统计量,我们计算另一个称为p 值的值(稍后我们将看到它对应于曲线下的面积)。如果 p 值大于事先选择的阈值(alpha),我们不能拒绝零假设,它继续保持为真实的。如果它较小,我们可以拒绝它,并确认新的(备择)假设。

当然,这种拒绝的置信度由我们事先选择的阈值给出。常见的阈值值是 0.1、0.5 和 0.001。它越小,我们的置信度就越高。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/b6b301d884e81bb7fa558834ab63348d.png

假设检验(图片由作者提供)

如果这仍然不是很清楚,不要担心,整个解释只需几行 Python 代码就可以实现!Scipy 库中的 t-test 函数直接返回测试统计量值和 p 值。我们只需要选择 alpha 值并做出决策。

Deepnote

在机器学习中,拥有一个参考数据集并与新获得的数据集进行比较是最优的,这样我们才能了解数据分布是否保持不变。不幸的是,我们通常没有那么多数据集可供使用,所以通常的做法是将测试数据集与训练数据集进行比较

常常进行的一项测试是确定两个特征是否来自相同的概率分布,当然,我们希望用于测试数据集的列与训练数据集具有相同的分布,否则,模型在测试中学习到的模式将完全无用!

要做到这一点,我们可以使用一种称为柯尔莫哥洛夫-斯米尔诺夫检验的测试。这个测试也由 scipy 库提供。

Deepnote

到目前为止,你应该能够使用 PyTest 实现这样的检查。

Deepnote

实际上,当我们对数据集的不同列进行多个假设检验时,我们必须对选择的 alpha 值进行修正,称为 Bonferroni 修正,我们将在下一篇文章中看到。

结论

在这篇文章中,我们讨论了数据摄取管道的主要组件,称为 ETL,它代表提取、转换和加载。我们还讨论了数据科学家验证其正在工作的数据的重要性。验证可以通过确定性测试来完成,其中我们事先知道预期的输出,以及可以通过统计测试来断言假设的非确定性测试。所有这些测试都是使用 PyTets 启动的,这是所有数据科学家都非常重要的工具,它帮助我们保持代码整洁并最小化代码中的错误。

如果你对这篇文章感兴趣,请关注我的Medium! 😁

💼 领英 ️| 🐦 X (Twitter) | 💻 网站

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/26 20:02:45

LSTM在CTC语音唤醒中的应用:小云小云时序建模优化

LSTM在CTC语音唤醒中的应用:小云小云时序建模优化 1. 引言 "小云小云"这个唤醒词你可能不陌生,它就像智能设备的"耳朵",让设备知道你在呼唤它。但要让这个"耳朵"在各种环境下都能准确识别,背后的…

作者头像 李华
网站建设 2026/3/14 16:30:00

NS-USBLoader全功能指南:让Switch管理变得简单高效

NS-USBLoader全功能指南:让Switch管理变得简单高效 【免费下载链接】ns-usbloader Awoo Installer and GoldLeaf uploader of the NSPs (and other files), RCM payload injector, application for split/merge files. 项目地址: https://gitcode.com/gh_mirrors/…

作者头像 李华
网站建设 2026/3/25 23:31:22

AI视频创作新选择:AnimateDiff写实风格生成全解析

AI视频创作新选择:AnimateDiff写实风格生成全解析 1. 为什么写实风视频生成突然变得简单了? 你有没有试过对着一段文字,想象它动起来的样子?微风吹起发丝的弧度、海浪拍岸时水花飞溅的瞬间、人物眨眼时睫毛投下的阴影——这些细节…

作者头像 李华
网站建设 2026/3/15 13:25:36

RMBG-2.0开源大模型实战:HuggingFace Space一键体验+源码链接

RMBG-2.0开源大模型实战:HuggingFace Space一键体验源码链接 1. 轻量级AI图像背景去除新选择 RMBG-2.0是一款开源的轻量级AI图像背景去除工具,它让专业级的图像处理变得触手可及。相比传统抠图工具需要复杂操作和专业技巧,RMBG-2.0通过AI技…

作者头像 李华
网站建设 2026/3/26 5:14:34

3款强力视频格式转换工具完全指南:让每个人都能掌控数字媒体

3款强力视频格式转换工具完全指南:让每个人都能掌控数字媒体 【免费下载链接】QMCDecode QQ音乐QMC格式转换为普通格式(qmcflac转flac,qmc0,qmc3转mp3, mflac,mflac0等转flac),仅支持macOS,可自动识别到QQ音乐下载目录&#xff0c…

作者头像 李华