Pandas DataFrame 高效比较:仅保留差异行与列的教程

Pandas DataFrame 高效比较:仅保留差异行与列的教程

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

在数据分析和处理中,我们经常需要对比两个结构相似的pandas dataframe,以找出它们之间的差异。例如,在版本控制、数据更新审计或a/b测试结果分析等场景下,快速定位并只关注那些发生变化的行和列是至关重要的。本教程将指导您如何利用pandas库的强大功能,实现这一目标。

场景描述与挑战

假设我们有两个DataFrame,df1和df2,它们包含相同的结构和大部分相同的数据,但某些行或列的特定值可能存在差异。我们的目标是生成一个新的DataFrame,其中只包含那些发生变化的行(及其对应的维度列)以及发生变化的具体列。

考虑以下两个示例DataFrame:

DataFrame 1 (df1):

pet_name exam_day result_1 result_2 pre_result_1

Patrick2023-01-01110123Patrick2023-01-02220123Patrick2023-01-03330123Patrick2023-01-04440123

DataFrame 2 (df2):

pet_name exam_day result_1 result_2 pre_result_1

Patrick2023-01-01110123Patrick2023-01-029920123Patrick2023-01-03330123Patrick2023-01-044100123

在这个例子中,df1和df2在以下位置存在差异:

pet_name=’Patrick’, exam_day=’2023-01-02′ 的 result_1 列pet_name=’Patrick’, exam_day=’2023-01-04′ 的 result_2 列

我们希望最终的输出DataFrame只包含这些差异,以及用于标识这些差异的维度列(pet_name和exam_day),例如:

pet_name exam_day result_1 result_2

Patrick2023-01-022NaNPatrick2023-01-0299NaNPatrick2023-01-04NaN40Patrick2023-01-04NaN100

传统的 merge(…, indicator=True, how=’outer’) 方法虽然能识别出有差异的行,但它会保留所有列,并且对同一行中的多个差异处理不够直观。为了达到上述精确的差异报告效果,Pandas提供了更专业的工具

使用 DataFrame.compare 方法

Pandas 1.1.0 版本引入的 DataFrame.compare 方法是解决此类问题的理想工具。它专门用于比较两个DataFrame,并以一种清晰的格式突出显示差异。

核心步骤

设置索引: 首先,将用于标识唯一记录的维度列(例如 pet_name 和 exam_day)设置为DataFrame的索引。这使得 compare 方法能够基于这些键进行行匹配和比较。执行比较: 调用 compare 方法,传入另一个DataFrame和 align_axis=0 参数。align_axis=0 表示按行对齐并比较列值。处理多级列索引: compare 方法的输出会有一个多级列索引,其中包含原始列名和指示差异来源(self 或 other)的内层索引。我们需要移除这个内层索引,以便后续处理。重置索引: 最后,将之前设置的维度索引重置为常规列,使其成为最终输出DataFrame的一部分。

示例代码

import pandas as pdimport numpy as np# 示例数据data1 = {    '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], # result_1 for 2023-01-02 is different    'result_2': [10, 20, 30, 100], # result_2 for 2023-01-04 is different    'pre_result_1': [123, 123, 123, 123]}df2 = pd.DataFrame(data2)print("df1:")print(df1)print("ndf2:")print(df2)# 1. 将维度列设置为索引# 2. 调用 compare 方法,align_axis=0 表示按行比较列# 3. 移除多级列索引中的内层 ('self', 'other')# 4. 重置索引,将维度列变回常规列out = (df1.set_index(['pet_name', 'exam_day'])          .compare(df2.set_index(['pet_name', 'exam_day']), align_axis=0)          .droplevel(-1, axis=1) # 移除最内层索引 (self/other)          .reset_index())print("n差异结果:")print(out)

输出解析

运行上述代码,您将得到如下输出:

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差异结果:  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

可以看到,最终的 out DataFrame 准确地捕获了 df1 和 df2 之间的所有差异。对于每个有差异的行,它会生成两行记录:一行显示 df1 中的值(self),另一行显示 df2 中的值(other)。没有差异的列则显示 NaN。

详细步骤说明

df1.set_index([‘pet_name’, ‘exam_day’]):这将 pet_name 和 exam_day 列设置为DataFrame的索引。compare 方法会使用这些索引来匹配并比较对应的行。.compare(df2.set_index([‘pet_name’, ‘exam_day’]), align_axis=0):这是核心的比较操作。df2.set_index(…) 确保两个DataFrame在比较前具有相同的索引结构。align_axis=0 参数告诉 compare 方法在行级别进行对齐和比较。它会查找两个DataFrame中索引相同的行,并比较这些行中所有列的值。只有存在差异的列才会被保留在结果中。此步骤的直接输出将是一个具有多级列索引的DataFrame,例如:

                         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

其中,列名是原始列名,第二级索引 self 和 other 指示该值来自哪个DataFrame。

.droplevel(-1, axis=1):这一步非常关键,它移除了列索引的最后一级(即 self 和 other 标识)。这样做是为了让结果DataFrame的列结构更简洁,只保留原始的列名。axis=1 指定操作对象是列索引。.reset_index():最后,将之前设置为索引的 pet_name 和 exam_day 列重新转换回常规的数据列。这样,它们就作为标识符与差异值一同呈现在最终结果中。

注意事项与最佳实践

索引选择: 确保您选择的索引列能够唯一标识DataFrame中的每一条记录。如果索引不唯一,compare 方法可能无法正确匹配行。数据类型: compare 方法在比较时会考虑数据类型。如果两个DataFrame中相同列的数据类型不同(例如,一个为整数,另一个为浮点数),即使值在数值上相同,也可能被识别为差异。缺失值 (NaN): compare 方法会将 NaN 视为一个值进行比较。如果两个DataFrame在同一位置都为 NaN,则不会被视为差异。如果一个为 NaN 另一个为实际值,则会被视为差异。性能: 对于非常大的DataFrame,set_index 和 compare 操作可能会消耗较多内存和时间。在处理海量数据时,请考虑其性能影响。列的增减: compare 方法主要用于比较结构相似的DataFrame。如果两个DataFrame的列集存在显著差异(例如,一个DataFrame有而另一个没有某个列),compare 默认只会比较两个DataFrame都存在的列。

总结

DataFrame.compare 方法是Pandas中一个强大且直观的工具,专门用于识别并提取两个DataFrame之间的差异。通过合理地设置索引并进行后续处理,我们可以生成一个高度定制化的差异报告,仅显示发生变化的行和列,这对于数据审计、变更追踪和版本控制等任务具有极高的实用价值。掌握这一方法,将显著提升您在处理和分析数据变更时的效率。

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

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

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月14日 12:50:40
下一篇 2025年12月14日 12:50:52

相关推荐

  • 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
  • Python中NumPy计算加速:如何利用多进程避免数据拷贝瓶颈

    本文深入探讨了Python中利用多进程加速NumPy密集型计算时遇到的性能瓶颈。常见的process_map方法在处理大型NumPy数组时,由于频繁的数据拷贝导致效率低下甚至慢于单线程。教程将揭示这一问题根源,并提供一个高效的解决方案:利用multiprocessing.Manager实现数据共享,…

    2025年12月14日
    000
  • 使用 Pandas 高效关联多文件数据并提取特定信息

    本教程详细介绍了如何利用 Python 的 Pandas 库,高效地处理来自多个文本文件的关联数据。通过将文件内容加载到 DataFrame 中,并运用 merge 操作进行数据整合,实现 IP 地址、MAC 地址和端口信息的精确匹配与提取,最终生成结构化的输出结果,避免了传统文件处理的复杂性。 场…

    2025年12月14日
    000
  • Pytesseract在特定IDE中无法找到Tesseract的解决方案

    本文旨在解决Pytesseract在部分IDE(如PyCharm)中出现TesseractNotFoundError,而在其他IDE(如VS Code)中正常工作的问题。即使Tesseract OCR引擎已正确安装并存在于系统PATH中,此问题仍可能发生。核心解决方案是通过显式设置pytessera…

    2025年12月14日
    000

发表回复

登录后才能评论
关注微信