如何在 Pandas 中的列子集上找到两个数据框中的 "set difference" 行?

How can I find the "set difference" of rows in two dataframes on a subset of columns in Pandas?

我有两个数据框,比如 df1df2,具有相同的列名。

示例:

df1

C1 | C2 | C3 | C4
A    1    2    AA
B    1    3    A
A    3    2    B

df2

C1 | C2 | C3 | C4
A    1    3    E
B    1    2    C
Q    4    1    Z

我想根据 df1df2 之间的固定列子集中的公共值过滤掉 df1 中的行。在上面的例子中,如果列是 C1C2,我想过滤掉前两行,因为它们在 df1df2 中的值这些列是相同的。

在 Pandas 中执行此操作的干净方法是什么?

到目前为止,基于this answer,我已经找到了共同的行。

common_df = pandas.merge(df1, df2, how='inner', on=['C1','C2'])

这给了我一个新的数据框,其中只有那些在指定列中具有共同值的行,即交集。

我也看到了 this thread,但答案似乎在所有列上都不同。

上述示例的预期结果(删除指定列上的公共行):

C1 | C2 | C3 | C4
A    3    2    B

可能不是最干净的,但您可以向 df1 添加一个键列以进行检查。

设置数据集

import pandas as pd
df1 = pd.DataFrame({ 'C1': ['A', 'B', 'A'],
            'C2': [1, 1, 3],
            'C3': [2, 3, 2],
            'C4': ['AA', 'A', 'B']})
df2 = pd.DataFrame({ 'C1': ['A', 'B', 'Q'],
            'C2': [1, 1, 4],
            'C3': [3, 2, 1],
            'C4': ['E', 'C', 'Z']})

添加密钥,使用您的代码查找公地

df1['key'] = range(1, len(df1) + 1)
common_df = pd.merge(df1, df2, how='inner', on=['C1','C2'])
df_filter = df1[~df1['key'].isin(common_df['key'])].drop('key', axis=1)

您可以使用反连接方法,在指定列上执行外部连接,同时返回带有指示符的连接方法。唯一的缺点是您必须在连接后重命名并删除额外的列。

>>> import pandas as pd
>>> df1 = pd.DataFrame({'C1':['A','B','A'],'C2':[1,1,3],'C3':[2,3,2],'C4':['AA','A','B']})
>>> df2 = pd.DataFrame({'C1':['A','B','Q'],'C2':[1,1,4],'C3':[3,2,1],'C4':['E','C','Z']})
>>> df_merged = df1.merge(df2, on=['C1','C2'], indicator=True, how='outer')
>>> df_merged
  C1  C2  C3_x C4_x  C3_y C4_y      _merge
0  A   1   2.0   AA   3.0    E        both
1  B   1   3.0    A   2.0    C        both
2  A   3   2.0    B   NaN  NaN   left_only
3  Q   4   NaN  NaN   1.0    Z  right_only
>>> df1_setdiff = df_merged[df_merged['_merge'] == 'left_only'].rename(columns={'C3_x': 'C3', 'C4_x': 'C4'}).drop(['C3_y', 'C4_y', '_merge'], axis=1)
>>> df1_setdiff
  C1  C2   C3 C4
2  A   3  2.0  B
>>> df2_setdiff = df_merged[df_merged['_merge'] == 'right_only'].rename(columns={'C3_y': 'C3', 'C4_y': 'C4'}).drop(['C3_x', 'C4_x', '_merge'], axis=1)
>>> df2_setdiff
  C1  C2   C3 C4
3  Q   4  1.0  Z
import pandas as pd
df1 = pd.DataFrame({'C1':['A','B','A'],'C2':[1,1,3],'C3':[2,3,2],'C4':['AA','A','B']})
df2 = pd.DataFrame({'C1':['A','B','Q'],'C2':[1,1,4],'C3':[3,2,1],'C4':['E','C','Z']})
common = pd.merge(df1, df2,on=['C1','C2'])
R1 = df1[~((df1.C1.isin(common.C1))&(df1.C2.isin(common.C2)))]
R2 = df2[~((df2.C1.isin(common.C1))&(df2.C2.isin(common.C2)))]

df1:

    C1  C2  C3  C4
0   A   1   2   AA
1   B   1   3   A
2   A   3   2   B

df2:

    C1  C2  C3  C4
0   A   1   3   E
1   B   1   2   C
2   Q   4   1   Z

常见:

    C1  C2   C3_x C4_x  C3_y C4_y
0   A   1    2    AA    3    E
1   B   1    3    A     2    C

R1:

    C1  C2  C3  C4
2   A   3   2   B

R2:

    C1  C2  C3  C4
2   Q   4   1   Z