
在数据分析和数据清洗过程中,我们经常需要比较两个结构相似的pandas dataframe,找出它们之间的差异,并了解这些差异行分别来自哪个原始dataframe。例如,比较当前估计数据与历史估计数据,以识别发生变化的条目。pandas提供了强大的合并(merge)功能,结合特定的参数,可以高效地完成这项任务。
要识别两个DataFrame的差异行并追踪其来源,最有效的方法是使用pd.merge函数进行outer(外连接)操作,并设置indicator=True参数。
通过过滤_merge列,我们可以轻松地提取出差异行(即_merge不等于'both'的行),并直接获取它们的来源信息。
假设我们有两个DataFrame,df_current_est(当前估计)和df_previous_est(先前估计),它们可能包含相同的列,我们希望找出两者之间不同的行,并标记这些行来自哪个原始DataFrame。
import pandas as pd
# 示例数据
df_current_est = pd.DataFrame({
'EstimateID': [10061, 10062, 10063],
'Season': [2023, 2023, 2023],
'RPIN': ['R1000', 'R2000', 'R3000'],
'GrowMethodCode': ['FO', 'FO', 'FO'],
'Variety_code': ['002', '068', '001'],
'Packout_pc': [0.60, 0.76, 0.80],
'QtyBins': [320, 1000, 500]
})
df_previous_est = pd.DataFrame({
'EstimateID': [10061, 10062, 10064],
'Season': [2023, 2023, 2023],
'RPIN': ['R1000', 'R2000', 'R4000'],
'GrowMethodCode': ['FO', 'FO', 'FO'],
'Variety_code': ['002', '068', '003'],
'Packout_pc': [0.60, 0.76, 0.90],
'QtyBins': [9000, 90000, 600] # 注意 QtyBins 差异
})
# 执行外连接并添加指示器
merged_df = pd.merge(df_current_est, df_previous_est, how='outer', indicator=True)
# 筛选出差异行(_merge不为'both'的行)
changed_df = merged_df[merged_df['_merge'] != 'both'].copy()
# 对结果进行排序以便观察
changed_df = changed_df.sort_values(by=['EstimateID', '_merge'], ascending=True)
print("识别出的差异行及其来源:")
print(changed_df)代码解释:
输出示例:
识别出的差异行及其来源: EstimateID Season RPIN GrowMethodCode Variety_code Packout_pc QtyBins _merge 0 10061 2023 R1000 FO 002 0.60 320 left_only 3 10061 2023 R1000 FO 002 0.60 9000 right_only 1 10062 2023 R2000 FO 068 0.76 1000 left_only 4 10062 2023 R2000 FO 068 0.76 90000 right_only 2 10063 2023 R3000 FO 001 0.80 500 left_only 5 10064 2023 R4000 FO 003 0.90 600 right_only
从输出可以看出,_merge列清晰地指示了每行是来自df_current_est(left_only)还是df_previous_est(right_only)。例如,EstimateID为10061的行在两个DataFrame中都有,但QtyBins值不同,因此它们都被标记为差异行,分别指示了各自的来源。
在获取到包含_merge列的结果后,如果你需要利用该列的信息来判断行的来源,请务必不要将其删除。原始问题中的代码片段就犯了这个错误:
# 错误示例:不应删除_merge列
changed_df.drop('_merge', axis=1, inplace=True)如果删除了_merge列,你将失去行的来源信息,这与你最初的目标相悖。
上述方法能够很好地追踪行的来源,但它不会保留原始DataFrame的索引。在某些场景下,你可能不仅关心行来自哪个DataFrame,还需要知道它在原始DataFrame中的具体索引。_merge列并不能保留原始索引信息。
如果需要保留原始索引,你需要在进行merge操作之前,先使用reset_index()方法将每个DataFrame的索引转换为一个普通的数据列。这样,在合并之后,原始索引信息就会作为新的列存在于结果DataFrame中。
import pandas as pd
# 示例数据,包含自定义索引
df1 = pd.DataFrame({'key': ['one', 'two', 'three'], 'value1': [1, 2, 3]},
index=[101, 102, 103])
df2 = pd.DataFrame({'key': ['two', 'four', 'three'], 'value2': [20, 40, 30]},
index=[201, 202, 203])
print("df1:")
print(df1)
print("\ndf2:")
print(df2)
# 将索引重置为列,然后进行外连接
merged_df_with_index = (
pd.merge(df1.reset_index(),
df2.reset_index(),
on='key', # 基于'key'列合并
suffixes=('_df1', '_df2'), # 为重复列添加后缀
how='outer',
indicator=True)
.query('_merge != "both"') # 筛选差异行
)
print("\n带有原始索引的差异行:")
print(merged_df_with_index)代码解释:
输出示例:
df1:
key value1
101 one 1
102 two 2
103 three 3
df2:
key value2
201 two 20
202 four 40
203 three 30
带有原始索引的差异行:
index_df1 key value1 index_df2 value2 _merge
0 101.0 one 1.0 NaN NaN left_only
3 NaN four NaN 202.0 40.0 right_only现在,结果DataFrame中包含了index_df1和index_df2列,它们分别存储了差异行在df1和df2中的原始索引。对于left_only的行,index_df2为NaN;对于right_only的行,index_df1为NaN。
在某些分析场景中,你可能还需要找出那些在两个DataFrame中都匹配的行(即_merge == "both"),并获取它们在原始DataFrame中的最大索引。这在需要追踪最新版本或最高ID的匹配记录时非常有用。
# 查找匹配行(_merge == "both")的最大索引
max_id_same = (
pd.merge(df1.reset_index(),
df2.reset_index(),
on='key',
suffixes=('_df1', '_df2'),
how='outer',
indicator=True)
.query('_merge == "both"') # 筛选匹配行
)[['index_df1', 'index_df2']].max() # 选择索引列并取最大值
print("\n匹配行(_merge == \"both\")的最大索引:")
print(max_id_same)输出示例:
匹配行(_merge == "both")的最大索引: index_df1 103.0 index_df2 203.0 dtype: float64
这表明在df1中,匹配行的最大索引是103,在df2中是203。
本教程详细阐述了在Pandas中比较两个DataFrame并识别差异行的两种主要场景:
掌握这些技术,可以帮助你在数据分析工作中更精确地理解和管理DataFrame之间的变化,从而提高数据处理的效率和准确性。
以上就是Pandas DataFrame差异行识别与来源追踪教程的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号