如何比较含重复项的不同大小的Pandas DataFrame?
解决方案
可以通过统计每行的出现频次,计算两个DataFrame间的频次差异,再根据差异值重新生成包含重复项差异的结果。这种方法避免了逐行遍历,效率更高。
步骤1:定义频次统计函数
先实现一个函数,将DataFrame的每行转换为可哈希的元组,再统计每个元组的出现次数:
def get_counts(df): return df.apply(tuple, axis=1).value_counts()
步骤2:计算频次差异
分别统计两个DataFrame的行频次,再计算差值(不存在的行默认次数为0):
counts_df = get_counts(df) counts_df1 = get_counts(df1) # 计算两个频次的差值,fill_value=0处理仅在单个DF中出现的行 diff_counts = counts_df.sub(counts_df1, fill_value=0)
步骤3:生成差异结果
根据频次差的正负和绝对值,生成对应的行数据,可选择合并结果或拆分为两个独立结果:
合并所有差异行
result_rows = [] for row_tuple, count in diff_counts.items(): if count != 0: # 根据次数差的绝对值重复添加该行 result_rows.extend([row_tuple] * abs(count)) # 转换为DataFrame,列名与原DF一致 result = pd.DataFrame(result_rows, columns=df.columns) print(result)
输出(顺序不影响需求):
Animal Name 0 Dog Kate 1 Dog Robert 2 Snake Nate
拆分为两个独立结果
如果需要分别存储df比df1多的行,以及df1比df多的行:
# df中多出的行(含重复次数差异) df_extra = pd.DataFrame( [row for row, cnt in diff_counts.items() if cnt > 0 for _ in range(cnt)], columns=df.columns ) # df1中多出的行(含重复次数差异) df1_extra = pd.DataFrame( [row for row, cnt in diff_counts.items() if cnt < 0 for _ in range(-cnt)], columns=df.columns ) print("df多出的行:") print(df_extra) print("\ndf1多出的行:") print(df1_extra)
输出:
df多出的行: Animal Name 0 Dog Kate 1 Dog Robert df1多出的行: Animal Name 0 Snake Nate
完整可运行代码
import pandas as pd # 创建示例DataFrame df = pd.DataFrame({'Animal': ['Cat', 'Dog', 'Rabbit', 'Dog', 'Dog'], 'Name': ['Peter', 'Kate', 'Bas', 'Kate', 'Robert']}) df1 = pd.DataFrame({'Animal': ['Snake', 'Cat', 'Dog', 'Rabbit'], 'Name': ['Nate', 'Peter', 'Kate', 'Bas']}) def get_counts(df): return df.apply(tuple, axis=1).value_counts() counts_df = get_counts(df) counts_df1 = get_counts(df1) diff_counts = counts_df.sub(counts_df1, fill_value=0) # 合并结果 result_rows = [] for row_tuple, count in diff_counts.items(): if count != 0: result_rows.extend([row_tuple] * abs(count)) result = pd.DataFrame(result_rows, columns=df.columns) print("合并的差异结果:") print(result) # 拆分结果 df_extra = pd.DataFrame([row for row, cnt in diff_counts.items() if cnt>0 for _ in range(cnt)], columns=df.columns) df1_extra = pd.DataFrame([row for row, cnt in diff_counts.items() if cnt<0 for _ in range(-cnt)], columns=df.columns) print("\ndf多出的行:") print(df_extra) print("\ndf1多出的行:") print(df1_extra)
原理说明
- 用
apply(tuple, axis=1)将每行转为元组,解决DataFrame行无法直接作为统计键的问题; value_counts()高效统计每行的出现次数,得到“行内容-次数”的映射关系;sub方法自动对齐两个频次Series的键,计算次数差,缺失键默认填充0,精准得到每行在两个DF中的数量差异;- 最后根据次数差的绝对值还原行数据,完全保留重复项的数量差异,且全程利用pandas向量化操作,比逐行遍历效率提升显著。
内容的提问来源于stack exchange,提问作者Nomeon
相关产品推荐
相关产品推荐

