news 2026/2/1 20:10:58

如何轻松使用 Pandera 验证数据

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
如何轻松使用 Pandera 验证数据

原文:towardsdatascience.com/how-to-easily-validate-your-data-with-pandera-a9cd22c515a5?source=collection_archive---------7-----------------------#2024-08-14

学习如何构建一个简单的数据模型,通过类型提示来验证数据

https://medium.com/@conalhenderson?source=post_page---byline--a9cd22c515a5--------------------------------https://towardsdatascience.com/?source=post_page---byline--a9cd22c515a5-------------------------------- Conal Henderson

·发布于Towards Data Science ·阅读时间:6 分钟·2024 年 8 月 14 日

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

图片来自Christina Morillo在Pixels

许多网上的pandas教程教授如何操作和清理数据,但很少有教程展示如何验证数据是否正确。这就是使用pandera进行数据验证的意义所在。

为什么需要数据验证?

就像任何人一样,当我第一次查看数据时,我会进行基本的调查,比如查看数据类型、检查空值,并可视化数据分布,来大致判断如何处理数据。

然而,我们需要数据验证来确保数据遵循业务逻辑。例如,对于包含产品信息的数据,我们需要验证产品价格没有负值;或者当用户提供电子邮件地址时,我们需要验证该电子邮件地址符合已知的模式。

忽视数据验证会对分析和建模产生下游影响,因为数据质量差会导致偏差、噪声和不准确性增加

最近一个数据验证不当的例子是Zillow 的房价算法,其高估了 Zillow 所购买的 2/3 的房产,导致 2021 年第三季度和第四季度 Zillow 房产估值下降了 5 亿美元。

这表明,你不仅需要关注数据是否符合验证标准,还需要关注数据是否反映了现实情况,而在 Zillow 的案例中,数据并未做到这一点。

什么是 Pandera?

[Pandera](https://pandera.readthedocs.io/en/stable/index.html)是一个 Python 包,提供了一个文档齐全且灵活的 API,能够与pandaspolars这两个主要的 Python 数据库进行集成。

我们可以使用pandera通过业务逻辑和领域知识来验证数据框架的数据类型和属性。

大纲

本文将覆盖以下内容:

设置

安装依赖

pip install pandas pip install pandera

数据

本文使用的数据是通过 Claude.ai 生成的假足球市场数据。

定义验证模型

该包允许你定义验证模式或数据验证模型,后者与另一个很棒的数据验证包[Pydantic](https://docs.pydantic.dev/latest/)非常相似。

对于本次练习,我们将专注于验证模型,因为它允许与我们的 Python 代码集成类型提示,并且我发现它比验证模式稍微更易于阅读。然而,如果你想利用验证模式,模型也有方法将其转换为模式。

你可以在这里找到关于两种验证方法的信息:

加载数据

data={'dob':pd.to_datetime(['1990-05-15','1988-11-22','1995-03-10','1993-07-30','1992-01-18','1994-09-05','1991-12-03','1989-06-20','1996-02-14','1987-08-08']),'age':[34,35,29,31,32,30,32,35,28,37],'country':['England','Spain','Germany','France','Italy','Brazil','Argentina','Netherlands','Portugal','England'],'current_club':['Manchester United','Chelsea','Bayern Munich','Paris Saint-Germain','Juventus','Liverpool','Barcelona','Ajax','Benfica','Real Madrid'],'height':pd.array([185,178,None,176,188,182,170,None,179,300],dtype='Int16'),'name':['John Smith','Carlos Rodriguez','Hans Mueller','Pierre Dubois','Marco Rossi','Felipe Santos','Diego Fernandez','Jan de Jong','Rui Silva','Gavin Harris'],'position':['Forward','Midfielder','Defender','Goalkeeper','Defender','Forward','Midfielder','Defender','Forward','Midfielder'],'value_euro_m':[75.5,90.2,55.8,40.0,62.3,88.7,70.1,35.5,45.9,95.0],'joined_date':pd.to_datetime(['2018-07-01','2015-08-15',None,'2017-06-30','2016-09-01',None,'2021-07-15','2014-08-01','2022-01-05','2019-06-01']),'number':[9,10,4,1,3,11,8,5,7,17],'signed_from':['Everton','Atletico Madrid','Borussia Dortmund',None,'AC Milan','Santos',None,'PSV Eindhoven','Sporting CP','Newcastle United'],'signing_fee_euro_m':[65.0,80.5,45.0,None,55.0,75.2,60.8,None,40.5,85.0],'foot':['right','left','right','both','right','left','left','right','both','right'],}df=pd.DataFrame(data)

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

图片来自作者

检查数据类型

data.types

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

图片来自作者

我们可以使用数据类型来帮助定义我们的数据模型。

创建数据模型

classPlayerSchema(pa.DataFrameModel):dob:Series[pd.Timestamp]=pa.Field(nullable=False,ge=pd.Timestamp('1975-01-01'))age:Series[pa.Int64]=pa.Field(ge=0,le=50,nullable=False)country:Series[pa.String]=pa.Field(nullable=False)current_club:Series[pa.String]=pa.Field(nullable=False)height:Series[pa.Int16]=pa.Field(ge=120,le=210,nullable=True)name:Series[pa.String]=pa.Field(nullable=False)position:Series[pa.String]=pa.Field(nullable=False)value_euro_m:Series[pa.Float64]=pa.Field(ge=0,le=200)joined_date:Series[pd.Timestamp]=pa.Field(nullable=True,ge=pd.Timestamp('2000-01-01'))number:Series[pa.Int64]=pa.Field(ge=0,le=99)signed_from:Series[pa.String]=pa.Field(nullable=True)signing_fee_euro_m:Series[pa.Float64]=pa.Field(ge=0,le=300,nullable=True)foot:Series[pa.String]=pa.Field(nullable=False,isin=['right','left','both','unknown'])

上面,我们通过子类化pa.DataFrameModel定义了一个模式,这与在[Pydantic](https://docs.pydantic.dev/latest/)中子类化BaseModel的方式相同。然后,我们用相应的数据集中的列填充了该模式,提供了每列的预期数据类型,并使用pa.Field方法定义了边界

Panderapandas的集成非常好,意味着你可以使用pandas数据类型(例如pd.Timestamp)以及 pandera 数据类型(例如pa.Int64)来定义每一列。

重用字段

为了避免重复字段,我们可以通过使用内建的 Python 库functools中的partial来重用字段。

fromfunctoolsimportpartial NullableField=partial(pa.Field,nullable=True)NotNullableField=partial(pa.Field,nullable=False)

partial类创建了一个应用原始函数指定子集参数的新函数

上面,我们为模型变量创建了两个可重用字段,这些变量要么包含空值,要么不包含空值。

我们更新后的数据模型如下所示

classPlayerSchema(pa.DataFrameModel):dob:Series[pd.Timestamp]=pa.Field(nullable=False,ge=pd.Timestamp('1975-01-01'))age:Series[pa.Int64]=pa.Field(ge=0,le=50,nullable=False)country:Series[pa.String]=NotNullableField()current_club:Series[pa.String]=NotNullableField()height:Series[pa.Int16]=pa.Field(ge=120,le=250,nullable=True)name:Series[pa.String]=NotNullableField()position:Series[pa.String]=NotNullableField()value_euro_m:Series[pa.Float64]=pa.Field(ge=0,le=200)joined_date:Series[pd.Timestamp]=pa.Field(nullable=True,ge=pd.Timestamp('2000-01-01'))number:Series[pa.Int64]=pa.Field(ge=0,le=99)signed_from:Series[pa.String]=NullableField()signing_fee_euro_m:Series[pa.Float64]=pa.Field(ge=0,le=300,nullable=True)foot:Series[pa.String]=pa.Field(nullable=False,isin=['right','left','both','unknown'])

由于partial创建了一个新函数,我们必须使用括号来调用我们的新字段。

验证数据

现在数据模型已经定义好,我们可以用它来验证数据。

@pa.check_typesdefload_data()->DataFrame[PlayerSchema]:returnpd.read_parquet('../data/player_info_cleaned.parquet')

为了验证数据,我们使用类型提示和装饰器的结合@pa.check_types装饰器表示数据应该按照返回类型提示DataFrame[PlayerSchema]中定义的模式进行验证。

@pa.check_typesdefvalidate_data(df:DataFrame)->DataFrame[PlayerSchema]:try:returndfexceptpa.errors.SchemaErrorase:print(e)validate_data(df)# error in check_types decorator of function 'load_data': Column 'height' failed element-wise validator number 1: less_than_or_equal_to(210) failure cases: 300

通过使用 try-except 块,我们可以捕获加载和验证数据时抛出的任何错误。结果显示,‘height’列未通过小于或等于测试,其中一个标记为 300cm 的身高是不正确的。

清理数据

清理数据有很多策略,其中一些我在之前的文章中已详细介绍。

[## 精通 Pandas 构建模块化和可重用的数据管道

通过利用 pandas 实现关键的数据处理策略,构建模块化、可重用且高效的数据管道。

medium.com](https://medium.com/@conalhenderson/master-pandas-to-build-modular-and-reusable-data-pipelines-1d12b003a423?source=post_page-----a9cd22c515a5--------------------------------)

为了简化处理,我将使用人口的中位数身高来填补所有大于 210cm 的值。

defclean_height(df:DataFrame)->DataFrame[PlayerSchema]:data=df.copy()data.loc[data[PlayerSchema.height]>210,PlayerSchema.height]=round(data[PlayerSchema.height].median())returndata df=clean_height(df)

pandera的另一个有用特性是,架构可以用来指定你想要分析的列名,例如,我们可以使用PlayerSchema.height提高代码的可读性并鼓励一致性,而不是显式地标记‘height’。

重新验证

由于我们的数据已经被加载进来,我们可以调整之前的函数,使其接受数据框作为输入,运行数据框并通过 try-except 块进行评估,并使用装饰器和类型提示。

validate_data_2(df)# if there are no errors, the dataframe is the output.

这次没有错误,意味着数据框被作为函数的输出返回。

结论

这篇文章概述了为什么验证数据非常重要,以确保数据与业务逻辑一致并反映现实世界,以 Zillow 为例,说明了缺乏数据验证可能带来的严重后果。

使用了Pandera来展示如何轻松地将数据验证与pandas集成,以快速验证一个架构,该架构与Pydantic非常相似,使用了装饰器类型提示。还展示了如何使用pa.Field设置数据的边界,并且当与partial一起使用时,可以创建可重用字段,从而提高代码的可读性。

希望你觉得这篇文章有用,感谢阅读。如果有任何问题,可以通过LinkedIn与我联系!

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

Agent基础:单代理 vs 多代理、Agent Loop、Memory 机制

以下是对单代理 vs 多代理、Agent Loop、Memory 机制的系统化讲解。这三者是构建智能体(Agent)系统的核心架构要素,直接影响 Agent 的能力边界、协作模式与长期行为一致性。一、定义解析概念全称/英文中文含义核心目标单代理(Sing…

作者头像 李华
网站建设 2026/1/30 21:14:17

别再堆 Prompt 了:用 LangChain 1.0 搭建“深度思考 Agent

“ 从“会聊天”到“会思考”:我用 LangChain 1.0 Qwen 做了一个旅游 Agent,一个真正能“思考”的旅游规划 Agent。 在这个过程中,我顺手把“深度思考(reasoning)”这一套,从 模型 → API → LangChain 1.…

作者头像 李华
网站建设 2026/1/30 22:09:54

‌从“找Bug的”到“质量倡导者”:敏捷时代测试工程师的价值重塑

在传统瀑布模型的记忆中,测试工程师的角色常常被简化为流水线的末端——一个严谨、细致,但略显被动的“质量守门员”。我们的形象,是与孤灯、用例和缺陷管理工具相伴,核心KPI是发现的Bug数量和缺陷严重等级。我们被称作“找Bug的”…

作者头像 李华
网站建设 2026/1/24 17:31:59

2025专科生必备!8个降AI率工具测评榜单

2025专科生必备!8个降AI率工具测评榜单 2025年专科生如何高效应对AI率问题? 随着高校对学术原创性的要求不断提高,AI生成内容(AIGC)检测系统已全面升级,许多学生在论文提交前遭遇“AI率超标”的尴尬局面。尤…

作者头像 李华