如何追踪两个表头相同但行数不同的DataFrame的变更?
问题描述
我有以下两个DataFrame:
第一个DataFrame:
col1 col2 a foo NaN b qux 2.0 c bar NaN d baz 4.0
第二个DataFrame:
col1 col2 a foo NaN c NaN 3.0 d baz 5.0 e xxx 6.0
我期望得到如下格式的Python字典:
out_dict = { "b": "deleted", #因为b在df2中已消失 "c": {"col1": None, "col2": 3}, #因为c的整行在df2中已更新 "d": {"col2": 5}, #因为仅d的col2在df2中已更新 "e": {"col1": "xxx", "col2": 6} #因为e是df2中新增的行 }
说明:两个DataFrame的表头始终相同,但行数可能不同。
创建这两个DataFrame的代码如下:
import pandas as pd import numpy as np df1 = pd.DataFrame({'col1': {'a': 'foo', 'b': 'qux', 'c': 'bar', 'd': 'baz'}, 'col2': {'a': np.nan, 'b': 2.0, 'c': np.nan, 'd': 4.0}}) df2 = pd.DataFrame({'col1': {'a': 'foo', 'c': np.nan, 'd': 'baz', 'e': 'xxx'}, 'col2': {'a': np.nan, 'c': 3.0, 'd': 5.0, 'e': 6.0}})
我尝试使用df1.compare(df2),但出现错误:
ValueError: Can only compare identically-labeled (both index and columns) DataFrame objects
恳请各位提供帮助 :)
解决方案
直接通过索引对比和值检查来生成目标字典,代码实现如下:
import pandas as pd import numpy as np df1 = pd.DataFrame({'col1': {'a': 'foo', 'b': 'qux', 'c': 'bar', 'd': 'baz'}, 'col2': {'a': np.nan, 'b': 2.0, 'c': np.nan, 'd': 4.0}}) df2 = pd.DataFrame({'col1': {'a': 'foo', 'c': np.nan, 'd': 'baz', 'e': 'xxx'}, 'col2': {'a': np.nan, 'c': 3.0, 'd': 5.0, 'e': 6.0}}) out_dict = {} # 处理被删除的行:df1有但df2没有的索引 deleted_indices = df1.index.difference(df2.index) for idx in deleted_indices: out_dict[idx] = "deleted" # 处理新增的行:df2有但df1没有的索引,转NaN为None added_indices = df2.index.difference(df1.index) for idx in added_indices: row_data = df2.loc[idx].replace({np.nan: None}).to_dict() out_dict[idx] = row_data # 处理有更新的行:对比共有的索引,收集值变化的列 common_indices = df1.index.intersection(df2.index) for idx in common_indices: changes = {} for col in df1.columns: val1 = df1.loc[idx, col] val2 = df2.loc[idx, col] # 跳过两个都是NaN的情况,否则检查值是否不同 if pd.isna(val1) and pd.isna(val2): continue elif val1 != val2: changes[col] = None if pd.isna(val2) else val2 if changes: out_dict[idx] = changes print(out_dict)
运行后输出:
{'b': 'deleted', 'c': {'col1': None, 'col2': 3.0}, 'd': {'col2': 5.0}, 'e': {'col1': 'xxx', 'col2': 6.0}}
注意:因为NaN本身不等于NaN,所以必须用pd.isna()来判断空值,避免误判;同时把df2中的NaN转为None,匹配目标字典的格式要求。
内容的提问来源于stack exchange,提问作者user21474411
相关产品推荐
相关产品推荐

