我有两个数据帧df1和df2,其中df2是df1的子集。我如何得到一个新的数据帧(df3),这是两个数据帧之间的差异?
换句话说,一个在df1中所有的行/列都不在df2中的数据帧?
我有两个数据帧df1和df2,其中df2是df1的子集。我如何得到一个新的数据帧(df3),这是两个数据帧之间的差异?
换句话说,一个在df1中所有的行/列都不在df2中的数据帧?
当前回答
对称差分
如果你只对其中一个数据帧中的行感兴趣,而不是两个数据帧中的行,你在寻找集的差异:
pd.concat([df1,df2]).drop_duplicates(keep=False)
⚠️只有在两个数据帧都不包含任何重复的情况下才有效。
设置差分/关系代数差分
如果你对关系代数差异/集差异感兴趣,即df1-df2或df1\df2:
pd.concat([df1,df2,df2]).drop_duplicates(keep=False)
⚠️只有在两个数据帧都不包含任何重复的情况下才有效。
其他回答
试试这个: Df_new = df1。merge(df2, how='outer', indicator=True)。查询('_merge == "left_only"')。下降(_merge, 1)
它将产生一个新的数据框架,其差异是:df1中存在的值,而df2中不存在。
正如这里提到的 那
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)
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
Pandas现在提供了一个新的API来处理数据帧差异:Pandas . datafframe .compare
df.compare(df2)
col1 col3
self other self other
0 a c NaN NaN
2 NaN NaN 3.0 4.0
方法1对于有nan的数据帧无效,因为pd.np.nan != pd.np.nan !我不确定这是否是最好的方法,但它可以避免
df1[~df1.astype(str).apply(tuple, 1).isin(df2.astype(str).apply(tuple, 1))]
它更慢,因为它需要将数据转换为字符串,但由于这个转换pd.np.nan == pd.np.nan。
让我们浏览一下代码。首先,我们将值转换为字符串,并将tuple函数应用于每一行。
df1.astype(str).apply(tuple, 1)
df2.astype(str).apply(tuple, 1)
多亏了这个,我们得到了pd。具有元组列表的系列对象。每个元组包含df1/df2的整行。 然后我们对df1应用isin方法来检查每个元组是否“在”df2中。 结果是pd。带有bool值的系列。如果tuple from df1在df2中,则为True。最后,我们用~符号对结果求反,并对df1进行滤波。长话短说,我们只能从df1中得到那些不在df2中的行。
为了使它更具可读性,我们可以这样写:
df1_str_tuples = df1.astype(str).apply(tuple, 1)
df2_str_tuples = df2.astype(str).apply(tuple, 1)
df1_values_in_df2_filter = df1_str_tuples.isin(df2_str_tuples)
df1_values_not_in_df2 = df1[~df1_values_in_df2_filter]