【问题标题】:Compare 2 DataFrames for semi matching rows比较 2 个 DataFrame 的半匹配行
【发布时间】:2021-09-04 14:04:24
【问题描述】:

我在单元格中有 2 个带有字符串的数据框:

df1

ID  t1  t2  t3
0   x1  y1  z1
1   x2  y2  z2 
2   x3  y3  z3 
3   x4  y4  z4  
4   x1  y5  z5 

df2

ID  t1  t2  t3
0   x3  y3  z3
1   x4  y4  z4 
2   x1  y1  z1 
3   x2  y2  z2  
4   x1  y7  z5 

我发现我可以将行中的差异与:

#exactly the same t1, t2, and t3
pd.merge(df1, df2, on=['t1', 't2', 't3'], how='inner')

这将找到行之间的精确匹配(其中 df1 中的 t1 等于 df2 中的 t1,等等)。

如何找到特定列的 2 个数据框之间的半匹配?也就是说,除了完全匹配之外,只有指定的列可能存在差异?例如,如果我指定t2,则匹配将是t1 in df1 = t1 in df2t2 in df1 != df2t3 in df1 = t3 in df3(例如,除了完全匹配之外,2 个数据帧中的行ID=4 将匹配此)。

更新 1:

似乎很多答案都考虑了顺序(如果行不完全对齐,该方法将失败)。

尝试以下方法来检查您的方法:

d1 = {'Entity1': ['x1', 'x2','x3','x4','x1', 'x6', 'x1'], 'Relationship': ['y1', 'y2','y3','y4','y5','y6', 'y9'], 'Entity2': ['z1', 'z2','z3','z4','z5','z6', 'z5']}
df1 = pd.DataFrame(data=d1)


d2 = {'Entity1': ['x3', 'x4','x1','x2','x6','x1'], 'Relationship': ['y3', 'y4','y1','y2','y6','y7'], 'Entity2': ['z3', 'z4','z1','z2','z7','z5']}
df2 = pd.DataFrame(data=d2)

请注意,精确匹配之一是x2, y2, z2,半匹配之一是df1 = x1, y5, z5df2 = x1, y7,z5

【问题讨论】:

  • 您正在寻找以下内容吗? df3 = pd.merge(df1, df2, on=['t1', 't2', 't3'], how='outer');df3[df3.isna().any(axis=1)]结果是逐行提取不匹配的行。
  • 您只想合并t1t3 吗? pd.merge(df1, df2, on=['t1', 't3'], how='inner')

标签: python dataframe


【解决方案1】:

您可以合并两个数据框,然后过滤所有 t1 和 t2 两边都相同的行:

df3 = pd.merge(df1, df2, left_index=True, right_index=True)
df3[(df3["t1_x"] == df3["t1_y"]) & (df3["t3_x"] == df3["t3_y"])]

【讨论】:

  • 真是太好了!这似乎给了我只有 1 个不匹配的数量(如 ID=4 行)。我怎样才能同时获得这些不匹配和完全匹配(来自问题“......除了完全匹配”)?我需要合并两个数据框吗?即合并来自pd.merge(df1, df2, on=['t1', 't2', 't3'], how='inner')的结果?我会裁员吗?
  • 您是在寻找匹配和半匹配,还是在寻找不匹配?
  • 不确定您将什么定义为半匹配与不匹配。除了完全匹配之外,我正在寻找其他列匹配的 1 列中的 1 个不匹配。此外,这似乎考虑了行的顺序(如果您切换行,它会失败)
【解决方案2】:

我在 cmets 中编写的代码是一种仅获取差异的方法。

df3 = pd.merge(df1, df2, on=['t1', 't2', 't3'], how='outer')
df3[df3.isna().any(axis=1)]

ID_x    t1  t2  t3  ID_y
4   4.0     x1  y5  z5  NaN
5   NaN     x1  y7  z5  4.0

如果需要,可以通过外连接检索所有不匹配和完全匹配。

df3 = pd.merge(df1, df2, on=['t1', 't2', 't3'], how='outer')

    ID_x    t1  t2  t3  ID_y
0   0.0     x1  y1  z1  2.0
1   1.0     x2  y2  z2  3.0
2   2.0     x3  y3  z3  0.0
3   3.0     x4  y4  z4  1.0
4   4.0     x1  y5  z5  NaN
5   NaN     x1  y7  z5  4.0

【讨论】:

  • 谢谢!但这假设行的顺序很重要(如果您在df2 中切换第 4 行和第 5 行,这将失败)
  • 我把df2的顺序改了,结果还是一样,怎么会失败呢?
【解决方案3】:

我写了一个通用的重型 function,它可以做你想要实现的事情以及更多(例如忽略某些列)

>>> dict1 = diff_func(df1, df2, uid=['t1','t3'], labels=('df1','df2'))
DataType check: Passed
Uniqueness check: ['t1', 't3']
df1: 5 out of 5 are unique (100.0%).
df2: 5 out of 5 are unique (100.0%).

获取t1t3 相同但t2 不同的数据框:

>>> dict1['Diff']                 
  df1 or df2  t1  t2  t3
0        df1  x1  y5  z5
1        df2  x1  y7  z5

名为df1 or df2 的列告诉您该行的来源,您可以通过扫描顶部和底部(而不是左右扫描)来直观地检查每一行以识别差异。 (想象一下有 50 列,并排视图将不具有可读性。)

获取所有列具有相同值的数据框(忽略索引):

>>> dict1['Merge']
   t1  t2  t3
0  x1  y1  z1
1  x2  y2  z2
2  x3  y3  z3
3  x4  y4  z4

相对于其中一个答案的优势在于,特定数据行是否具有不同的索引并不重要。请注意,您的x4, y4, z4 分别位于ID=3ID=1

请参考我的文章here以获得更详细的解释。

更新 1

我修改了code 以适应多行的情况,其中要比较的列具有相同的值。

>>> dict1['Diff']
  df1 or df2  Entity1  Relationship  Entity2
0        df1       x1            y5       z5
1        df1       x1            y9       z5
2        df2       x1            y7       z5

根据您的新示例,对于要比较的列,两个表中的记录值不同:

>>> dict1['Left_only']
  Entity1 Relationship Entity2
1      x6           y6      z6
>>> dict1['Right_only']
  Entity1 Relationship Entity2
3      x6           y6      z7

由于Entity2df1df2(也分别称为leftright 数据帧)中这两条记录不同,因此它们不在Diff 数据帧中。

【讨论】:

  • 谢谢!这似乎几乎可以工作。如果df1 中有 2 行也是匹配的(x1y9z5),这将停止工作
  • 现在应该可以了,我已经更新了初始页面中的代码以满足您提到的情况。
  • @Penguin:你检查我更新的代码了吗?
【解决方案4】:

eq 甚至更好:

>>> df3 = pd.merge(df1, df2, left_index=True, right_index=True)
>>> df3.loc[df1.eq(df2)[['t1', 't3']].all(1)]
   ID_x t1_x t2_x t3_x  ID_y t1_y t2_y t3_y
4     4   x1   y5   z5     4   x1   y7   z5
>>> 

这会合并数据帧,并在t1t3 两列上保留df1df2 相同的行。

编辑更新:

如果您还想匹配不同索引中的行,请尝试isin

print(df3[np.isin(df1, df2).any(1) & (~np.isin(df1, df2).all(1))].dropna())

输出:

  Entity1_x Relationship_x Entity2_x Entity1_y Relationship_y Entity2_y
4        x1             y5        z5        x6             y6        z7
5        x6             y6        z6        x1             y7        z5

【讨论】:

  • 谢谢!但这假设行的顺序很重要(如果您在df2 中切换第 4 行和第 5 行,这将失败)
  • @Penguin 是的,所有的答案都是这样,将编辑一个适用于所有行的答案
  • @Penguin 使用适用于无序行的内容编辑了我的答案,isin,请随时查看。
  • @Penguin 想要的输出是什么?
  • @Penguin 用可行的方法编辑了我的答案(如果我正确理解更新 1)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多