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

碧海醫心
发布: 2025-09-21 19:40:01
原创
570人浏览过

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

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

1. 引言与问题背景

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

考虑以下两个DataFrame df1 和 df2:

import pandas as pd

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], # 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_1
0  Patrick  2023-01-01         1        10           123
1  Patrick  2023-01-02         2        20           123
2  Patrick  2023-01-03         3        30           123
3  Patrick  2023-01-04         4        40           123

df2:
  pet_name    exam_day  result_1  result_2  pre_result_1
0  Patrick  2023-01-01         1        10           123
1  Patrick  2023-01-02        99        20           123
2  Patrick  2023-01-03         3        30           123
3  Patrick  2023-01-04         4       100           123
登录后复制

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

  pet_name    exam_day  result_1  result_2
0  Patrick  2023-01-02       2.0       NaN
1  Patrick  2023-01-02      99.0       NaN
2  Patrick  2023-01-04       NaN      40.0
3  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 实现步骤

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

行者AI
行者AI

行者AI绘图创作,唤醒新的灵感,创造更多可能

行者AI 100
查看详情 行者AI
  1. 设置索引: 将 pet_name 和 exam_day 这两个维度列设置为DataFrame的索引。这样做是为了确保 compare 方法能够正确地基于这些维度对齐和识别行。
  2. 执行比较: 调用 compare 方法,将 df2 作为 other 参数,并设置 align_axis=0。
  3. 后处理索引: compare 方法在 align_axis=0 模式下,如果原始索引不是唯一的,或者当我们将维度列设置为索引后,它会为结果DataFrame的行生成一个MultiIndex,其中包含一个额外的级别('self' 或 'other')来区分来自哪个DataFrame的数据。我们需要删除这个额外的级别。
  4. 重置索引: 将之前设置为索引的维度列(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_2
pet_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_2
0  Patrick  2023-01-02       2.0       NaN
1  Patrick  2023-01-02      99.0       NaN
2  Patrick  2023-01-04       NaN      40.0
3  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差异提取:仅保留差异行与列的教程的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
热门推荐
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号