我有两个数据帧df1和df2,其中df2是df1的子集。我如何得到一个新的数据帧(df3),这是两个数据帧之间的差异?

换句话说,一个在df1中所有的行/列都不在df2中的数据帧?


当前回答

对于行,尝试这样做,其中Name是联合索引列(可以是多个公共列的列表,或者指定left_on和right_on):

m = df1.merge(df2, on='Name', how='outer', suffixes=['', '_'], indicator=True)

indicator=True设置很有用,因为它添加了一个名为_merge的列,其中包含df1和df2之间的所有更改,分为3种可能的类型:“left_only”,“right_only”或“both”。

对于列,试试这个:

set(df1.columns).symmetric_difference(df2.columns)

其他回答

import pandas as pd
# given
df1 = pd.DataFrame({'Name':['John','Mike','Smith','Wale','Marry','Tom','Menda','Bolt','Yuswa',],
    'Age':[23,45,12,34,27,44,28,39,40]})
df2 = pd.DataFrame({'Name':['John','Smith','Wale','Tom','Menda','Yuswa',],
    'Age':[23,12,34,44,28,40]})

# find elements in df1 that are not in df2
df_1notin2 = df1[~(df1['Name'].isin(df2['Name']) & df1['Age'].isin(df2['Age']))].reset_index(drop=True)

# output:
print('df1\n', df1)
print('df2\n', df2)
print('df_1notin2\n', df_1notin2)

# df1
#     Age   Name
# 0   23   John
# 1   45   Mike
# 2   12  Smith
# 3   34   Wale
# 4   27  Marry
# 5   44    Tom
# 6   28  Menda
# 7   39   Bolt
# 8   40  Yuswa
# df2
#     Age   Name
# 0   23   John
# 1   12  Smith
# 2   34   Wale
# 3   44    Tom
# 4   28  Menda
# 5   40  Yuswa
# df_1notin2
#     Age   Name
# 0   45   Mike
# 1   27  Marry
# 2   39   Bolt

nice @liangli的解决方案略有变化,不需要改变现有数据框架的索引:

newdf = df1.drop(df1.join(df2.set_index('Name').index))

正如这里提到的 那

df1[~df1.apply(tuple,1).isin(df2.apply(tuple,1))]

是正确的解决方案,但它会产生错误的输出如果

df1=pd.DataFrame({'A':[1],'B':[2]})
df2=pd.DataFrame({'A':[1,2,3,3],'B':[2,3,4,4]})

在这种情况下,上面的溶液会给出 空数据帧,相反,你应该使用concat方法后,从每个数据帧删除重复。

使用concate和drop_duplicate

df1=df1.drop_duplicates(keep="first") 
df2=df2.drop_duplicates(keep="first") 
pd.concat([df1,df2]).drop_duplicates(keep=False)

也许是一个简单的单行程序,具有相同或不同的列名。即使df2['Name2']包含重复的值也能正常工作。

newDf = df1.set_index('Name1')
           .drop(df2['Name2'], errors='ignore')
           .reset_index(drop=False)

edit2,我想出了一个新的解决方案,不需要设置索引

newdf=pd.concat([df1,df2]).drop_duplicates(keep=False)

好吧,我发现最高投票的答案已经包含我已经弄明白了。是的,我们只能在每个dfs中没有重复的情况下使用此代码。


我有一个棘手的方法。首先,我们将“Name”设置为问题给出的两个数据框架的索引。由于我们在两个dfs中有相同的' Name ',我们可以从'大' df中删除'小' df的索引。 这是代码。

df1.set_index('Name',inplace=True)
df2.set_index('Name',inplace=True)
newdf=df1.drop(df2.index)