Pandas DataFrame差异提取:仅保留差异行与列的教程

pandas dataframe差异提取:仅保留差异行与列的教程

本教程详细阐述如何在Pandas中比较两个DataFrame,并高效地提取仅包含差异值所在的行和列。我们将利用DataFrame.compare方法,结合索引设置和后处理步骤,精确地识别并展示两个数据集中所有不同之处,同时保留关键的维度列,从而实现数据差异的精准分析与可视化。

1. 引言与问题背景

在数据分析和数据质量管理中,经常需要比较两个结构相似的DataFrame,以找出它们之间的具体差异。例如,比较同一数据集在不同时间点的快照,或者比较不同数据源中相同实体的信息。常见的需求是不仅要识别出有差异的行,还要进一步识别出这些行中具体是哪些列的值发生了变化,并最终只保留这些差异信息以及作为标识的维度列。

考虑以下两个DataFrame df1 和 df2:

import pandas as pddata1 = {    'pet_name': ['Patrick', 'Patrick', 'Patrick', 'Patrick'],    'exam_day': ['2023-01-01', '2023-01-02', '2023-01-03', '2023-01-04'],    'result_1': [1, 2, 3, 4],    'result_2': [10, 20, 30, 40],    'pre_result_1': [123, 123, 123, 123]}df1 = pd.DataFrame(data1)data2 = {    'pet_name': ['Patrick', 'Patrick', 'Patrick', 'Patrick'],    'exam_day': ['2023-01-01', '2023-01-02', '2023-01-03', '2023-01-04'],    'result_1': [1, 99, 3, 4], # Difference here (2 vs 99)    'result_2': [10, 20, 30, 100], # Difference here (40 vs 100)    'pre_result_1': [123, 123, 123, 123]}df2 = pd.DataFrame(data2)print("df1:")print(df1)print("ndf2:")print(df2)

输出:

df1:  pet_name    exam_day  result_1  result_2  pre_result_10  Patrick  2023-01-01         1        10           1231  Patrick  2023-01-02         2        20           1232  Patrick  2023-01-03         3        30           1233  Patrick  2023-01-04         4        40           123df2:  pet_name    exam_day  result_1  result_2  pre_result_10  Patrick  2023-01-01         1        10           1231  Patrick  2023-01-02        99        20           1232  Patrick  2023-01-03         3        30           1233  Patrick  2023-01-04         4       100           123

我们的目标是得到一个DataFrame,其中只包含 pet_name 和 exam_day 作为标识列,以及所有值存在差异的列。例如,对于上述数据,期望的输出应类似:

  pet_name    exam_day  result_1  result_20  Patrick  2023-01-02       2.0       NaN1  Patrick  2023-01-02      99.0       NaN2  Patrick  2023-01-04       NaN      40.03  Patrick  2023-01-04       NaN     100.0

可以看到,pre_result_1 列因其值在两个DataFrame中完全相同而被移除。

2. 使用 DataFrame.compare 方法

Pandas 提供了 DataFrame.compare 方法,专门用于执行元素级别的比较,并返回一个突出显示差异的DataFrame。这是实现我们目标的最有效工具

2.1 DataFrame.compare 简介

DataFrame.compare(other, align_axis=1, keep_equal=False, keep_shape=False)

other: 另一个要比较的DataFrame。align_axis: 指定如何对齐差异。0 或 ‘index’: 按行对齐,返回的DataFrame将具有一个MultiIndex行,其中包含原始索引和指示是来自self还是other的级别。1 或 ‘columns’: 按列对齐,返回的DataFrame将具有一个MultiIndex列,其中包含原始列名和指示是来自self还是other的级别。通常,为了识别行级差异,我们使用 align_axis=0。keep_equal: 布尔值,默认为 False。如果为 True,则即使列中的所有值都相同,也会保留该列。我们希望只保留差异列,因此保持默认 False。keep_shape: 布尔值,默认为 False。如果为 True,则返回的DataFrame将保留原始形状,并在没有差异的位置填充 NaN。我们希望只看到差异,因此保持默认 False。

compare 方法的强大之处在于它会自动识别并只返回那些值存在差异的列。

2.2 实现步骤

为了达到期望的输出,我们需要执行以下步骤:

设置索引: 将 pet_name 和 exam_day 这两个维度列设置为DataFrame的索引。这样做是为了确保 compare 方法能够正确地基于这些维度对齐和识别行。执行比较: 调用 compare 方法,将 df2 作为 other 参数,并设置 align_axis=0。后处理索引: compare 方法在 align_axis=0 模式下,如果原始索引不是唯一的,或者当我们将维度列设置为索引后,它会为结果DataFrame的行生成一个MultiIndex,其中包含一个额外的级别(’self’ 或 ‘other’)来区分来自哪个DataFrame的数据。我们需要删除这个额外的级别。重置索引: 将之前设置为索引的维度列(pet_name 和 exam_day)重新变回普通列。

下面是具体的实现代码:

# 1. 设置索引df1_indexed = df1.set_index(['pet_name', 'exam_day'])df2_indexed = df2.set_index(['pet_name', 'exam_day'])# 2. 执行比较# compare方法默认keep_equal=False,因此会自动移除完全相同的列diff_df_raw = df1_indexed.compare(df2_indexed, align_axis=0)print("--- 原始 compare 输出 ---")print(diff_df_raw)# 3. 后处理索引:删除由 compare 产生的 'self'/'other' 级别# 这个级别是行MultiIndex的最后一个级别diff_df_processed = diff_df_raw.droplevel(-1)# 4. 重置索引,将维度列变回普通列final_diff_df = diff_df_processed.reset_index()print("n--- 最终差异 DataFrame ---")print(final_diff_df)

代码解析与输出:

首先,df1_indexed.compare(df2_indexed, align_axis=0) 的输出 diff_df_raw 如下:

--- 原始 compare 输出 ---                           result_1  result_2pet_name exam_day                            Patrick  2023-01-02 self        2.0       NaN                    other      99.0       NaN         2023-01-04 self        NaN      40.0                    other       NaN     100.0

可以看到,compare 方法成功地识别了 result_1 和 result_2 列中的差异。它创建了一个MultiIndex行,其中包含 pet_name、exam_day 以及一个指示数据来源(self 或 other)的级别。同时,result_1 和 result_2 列本身也带有MultiIndex((‘result_1’, ‘self’), (‘result_1’, ‘other’) 等)。这里由于 keep_equal=False,pre_result_1 列被自动移除了。

然后,droplevel(-1) 操作移除了行MultiIndex中的最后一个级别(’self’ 或 ‘other’),使得行索引只剩下 (‘pet_name’, ‘exam_day’)。

最后,reset_index() 将 pet_name 和 exam_day 从索引变回普通列,得到我们期望的最终结果:

--- 最终差异 DataFrame ---  pet_name    exam_day  result_1  result_20  Patrick  2023-01-02       2.0       NaN1  Patrick  2023-01-02      99.0       NaN2  Patrick  2023-01-04       NaN      40.03  Patrick  2023-01-04       NaN     100.0

这个结果清晰地展示了两个DataFrame之间的所有差异,并且只保留了发生变化的列以及作为行标识的维度列。

3. 注意事项与最佳实践

索引的重要性: 在使用 compare 方法时,正确设置索引是至关重要的。如果你的DataFrame没有明确的唯一标识列,或者标识列并非唯一,compare 的行为可能会变得复杂。确保用于 set_index 的列组合能够唯一标识每一行。列的MultiIndex: DataFrame.compare 的默认输出在列上会创建一个MultiIndex,例如 (‘result_1’, ‘self’) 和 (‘result_1’, ‘other’)。在上述解决方案中,我们通过 droplevel 和 reset_index 处理了行索引。如果需要进一步处理列MultiIndex(例如,将它们展平或重命名),可能需要额外的步骤,例如使用 df.columns = df.columns.map(‘_’.join) 或 pd.MultiIndex.from_tuples。然而,对于本教程的目标,即只保留差异列,compare 的默认行为已经足够。数据类型: compare 方法对数据类型敏感。如果两个DataFrame中同一列的数据类型不同,即使值看起来相同,也可能被视为差异。确保比较前数据类型的一致性。缺失值 (NaN): compare 默认会将 NaN 与非 NaN 值视为不同。如果 NaN 与 NaN 之间应视为相同,则可能需要预处理,例如使用 fillna()。性能: 对于非常大的DataFrame,compare 方法的性能通常是高效的,因为它是在C语言层面实现的。然而,如果数据量极其庞大,仍需注意内存消耗。多列差异: 即使有300+列,compare 方法也能自动处理,它只会保留那些存在差异的列,极大地简化了差异分析工作。

4. 总结

通过 DataFrame.compare 方法,结合适当的索引设置和后处理,我们可以高效且准确地从两个Pandas DataFrame中提取出所有值存在差异的行和列。这种方法不仅简化了差异识别过程,而且提供了清晰、易于理解的差异报告,对于数据验证、版本控制和数据质量监控等场景都非常有用。掌握此技巧,将大大提升您在Pandas中处理数据差异的能力。

以上就是Pandas DataFrame差异提取:仅保留差异行与列的教程的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1373045.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月14日 12:51:04
下一篇 2025年12月14日 12:51:07

相关推荐

  • python如何从网页上下载图片_python爬虫下载网页图片实战方法

    答案:用Python下载网页图片需三步:获取网页内容、解析提取图片链接、下载保存。先用requests加headers获取HTML,再用BeautifulSoup解析img标签,处理相对路径,最后通过requests获取二进制数据并保存文件。 用Python从网页上下载图片,说白了,这事儿的核心逻辑…

    好文分享 2025年12月14日
    000
  • Django 的异常处理体系解析

    Django通过多层次机制处理异常,从Python原生try-except到框架级异常、中间件拦截及自定义错误页面。首先需关闭DEBUG模式,创建404.html和500.html模板,并在urls.py中配置handler404和handler500指向自定义视图函数,以提升用户体验与安全性。中间…

    2025年12月14日
    000
  • Pandas DataFrame 高效比较:仅保留差异行与列的教程

    本教程详细介绍了如何使用Pandas的compare方法高效地比较两个DataFrame,并仅提取出存在差异的行和列,同时保留指定的维度列。通过将维度列设为索引,compare方法能够识别数值变更,并通过后续处理生成一个简洁明了的差异报告,极大地简化了数据对比和变更追踪的过程。 在数据分析和处理中,…

    2025年12月14日
    000
  • python中字符串的encode()和decode()怎么用?

    Python中字符串的encode()和decode()方法用于在文本(str)与二进制数据(bytes)间转换,encode()将字符串按指定编码(如utf-8)转为字节串,decode()将字节串还原为字符串,需确保编解码格式一致,否则会引发UnicodeEncodeError或UnicodeD…

    2025年12月14日
    000
  • Matplotlib与Tkinter:实现精细化状态映射的自定义条形图

    本文探讨了在数据可视化中,如何突破传统Matplotlib堆叠条形图的局限,实现对数据中每个独立状态单元进行颜色映射的自定义图形。针对需要将每个检查结果(如成功或失败)以独立色块形式展示的需求,文章提出并详细阐述了使用Tkinter画布进行精细化绘图的解决方案,包括数据处理、图形元素绘制、布局调整及…

    2025年12月14日
    000
  • python中怎么用numpy进行矩阵运算?

    NumPy的ndarray因内存连续、类型一致、底层C实现及丰富函数库,在性能、功能和生态上全面优于Python嵌套列表,成为科学计算首选。 NumPy是Python进行高效矩阵运算的基石,它通过其核心的 ndarray 对象,为我们提供了处理多维数组和矩阵的强大能力,让原本复杂、耗时的数值计算变得…

    2025年12月14日
    000
  • pip 与 pip3 的区别与使用场景

    pip可能指向Python 2或3,依赖系统配置;pip3始终指向Python 3。在多版本系统中应使用pip3确保包安装到Python 3环境,避免导入错误。通过pip –version可查看其关联的Python版本。推荐始终使用pip3并配合虚拟环境,以保证环境清晰和项目兼容性。 在…

    2025年12月14日
    000
  • Mac 系统如何配置 Python 环境

    答案:通过Homebrew安装Python 3并配置虚拟环境。先安装Homebrew,再用brew install python获取最新版Python,设置别名使python命令指向python3,使用python3 -m venv创建虚拟环境隔离项目依赖,最后安装jupyter等常用工具完成开发环…

    2025年12月14日
    000
  • 使用Python subprocess模块运行带参数和输入重定向的外部命令

    本文详细阐述了如何利用Python的subprocess模块执行外部命令,特别是当命令包含连接字符串和输入重定向(如 挑战分析:Python调用外部命令的常见陷阱 在Python中,subprocess模块是执行外部命令和进程的强大工具。然而,当我们需要执行的命令包含特殊字符或操作符,例如数据库连接…

    2025年12月14日
    000
  • Python 异常处理在爬虫项目中的应用

    爬虫中常见的网络请求异常包括连接错误、超时和HTTP状态码异常,需通过try-except分层捕获并针对性处理。 在爬虫项目中,Python的异常处理机制绝不是可有可无的装饰品,它简直就是保障爬虫生命力与稳定性的核心骨架。没有它,你的爬虫就像在薄冰上跳舞,任何一点风吹草动——网络波动、目标网站结构微…

    2025年12月14日
    000
  • Python动态列表初始化中可变对象引用问题解析与规避

    在Python中,使用乘法运算符(*)初始化包含可变对象(如列表、字典)的嵌套列表时,会创建这些可变对象的浅拷贝,导致所有“副本”实际上都指向内存中的同一个对象。这使得修改其中一个元素会意外地影响到所有引用,从而产生非预期结果。本文将深入探讨这一常见陷阱,并提供使用列表推导式、显式循环以及colle…

    2025年12月14日
    000
  • Python中动态嵌套列表初始化陷阱与正确实践

    在Python中,使用乘法运算符*初始化嵌套列表时,可能会遇到内部可变对象被共享引用的陷阱,导致修改一个元素时意外影响所有副本。本文将深入探讨这一常见问题,并通过列表推导式、显式循环以及collections模块中的Counter等多种方法,指导开发者如何正确地动态创建独立的嵌套列表结构,避免数据污…

    2025年12月14日
    000
  • Python中动态多维列表初始化陷阱与解决方案

    在Python中,使用乘法运算符*初始化多维列表时,常会遇到子列表共享同一内存地址的陷阱,导致修改一个元素时意外影响所有关联元素。本文深入探讨了这一问题的原因,并通过代码示例展示了如何使用列表推导式或显式循环创建独立的子列表,同时介绍了collections模块中的defaultdict和Count…

    2025年12月14日
    000
  • 通过Python脚本执行psql命令,包含连接字符串和输入重定向

    本文详细介绍了如何使用Python的subprocess模块正确执行包含连接字符串和输入重定向(如 通过Python脚本执行外部命令的挑战 在python开发中,经常需要与外部命令行工具交互,例如执行数据库客户端(如psql.exe)进行数据导入或导出。subprocess模块是python中用于创…

    2025年12月14日
    000
  • cx_Oracle查询调试:如何查看实际执行的参数化SQL语句

    本文旨在指导如何在cx_Oracle中调试参数化SQL查询。我们将深入理解cx_Oracle如何安全地处理绑定变量,避免SQL注入,并介绍通过设置PYO_DEBUG_PACKETS环境变量来查看发送至数据库的实际数据包,从而验证查询语句和参数。此外,还将探讨查询无结果的常见原因,如遗漏数据获取操作或…

    2025年12月14日
    000
  • 如何在电脑上同时管理多个 Python 版本

    在开发不同项目时,经常会遇到需要使用不同 Python 版本的情况。比如一个老项目依赖 Python 3.7,而新项目用上了 Python 3.11。直接替换系统默认版本容易造成冲突。解决这个问题的关键是使用 Python 版本管理工具,让多个版本共存并按需切换。 使用 pyenv(推荐 macOS…

    2025年12月14日
    000
  • Python中基于相似度对字典条目进行分组:图论与最大团算法

    针对字典条目间的冗余相似性比较问题,本教程介绍了一种基于图论和最大团算法的优雅解决方案。通过为每个独特的相似度值构建一个图,并将字典键作为节点,相似条目间的边作为连接,我们可以利用networkx库高效地识别出具有相同相似度的最大分组(即最大团),从而将具有相同相似性分数的条目进行有效聚合,避免重复…

    2025年12月14日
    000
  • GTK2 Glade XML 文件到 GTK3 的迁移与转换指南

    本文旨在解决将GTK2.24 Glade XML用户界面定义迁移到GTK3兼容格式的挑战,尤其是在现代Glade版本不稳定时。我们重点介绍并详细阐述了官方推荐工具gtk-builder-convert的使用方法,帮助开发者高效、准确地完成UI文件升级,确保基于Python的应用程序能在GTK3环境下…

    2025年12月14日
    000
  • Epic FHIR应用OAuth2认证:JWK URL的理解与实现

    本文旨在详细阐述Epic FHIR OAuth2认证流程中JWK URL的角色与实现。不同于由Epic提供,JWK URL是一个由您的应用程序自行托管的端点,它包含了您的公钥集(JWKS)。Epic将通过此URL获取公钥,以验证您的应用程序在认证过程中使用私钥签名的JWT的真实性。文章将提供Djan…

    2025年12月14日
    000
  • Python脚本中执行psql.exe并处理I/O重定向

    本教程探讨如何在Python脚本中正确执行带有参数和I/O重定向(如 问题背景与挑战 在python脚本中执行外部命令行工具时,尤其当命令包含i/o重定向(如从文件读取输入 psql.exe postgresql://user:pass@host:port/ < backup.sql 用户可能…

    2025年12月14日
    000

发表回复

登录后才能评论
关注微信