我有两个数据帧df1和df2,其中df2是df1的子集。我如何得到一个新的数据帧(df3),这是两个数据帧之间的差异?
换句话说,一个在df1中所有的行/列都不在df2中的数据帧?
我有两个数据帧df1和df2,其中df2是df1的子集。我如何得到一个新的数据帧(df3),这是两个数据帧之间的差异?
换句话说,一个在df1中所有的行/列都不在df2中的数据帧?
当前回答
另一个可能的解决方案是使用numpy广播:
df1[np.all(~np.all(df1.values == df2.values[:, None], axis=2), axis=0)]
输出:
Name Age
1 Mike 45
4 Marry 27
7 Bolt 39
其他回答
通过索引查找差异。假设df1是df2的一个子集,并且在进行子集设置时将索引前移
df1.loc[set(df1.index).symmetric_difference(set(df2.index))].dropna()
# Example
df1 = pd.DataFrame({"gender":np.random.choice(['m','f'],size=5), "subject":np.random.choice(["bio","phy","chem"],size=5)}, index = [1,2,3,4,5])
df2 = df1.loc[[1,3,5]]
df1
gender subject
1 f bio
2 m chem
3 f phy
4 m bio
5 f bio
df2
gender subject
1 f bio
3 f phy
5 f bio
df3 = df1.loc[set(df1.index).symmetric_difference(set(df2.index))].dropna()
df3
gender subject
2 m chem
4 m bio
方法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]
通过使用drop_duplicate
pd.concat([df1,df2]).drop_duplicates(keep=False)
更新:
上面的方法只适用于那些本身没有副本的数据帧。例如:
df1=pd.DataFrame({'A':[1,2,3,3],'B':[2,3,4,4]})
df2=pd.DataFrame({'A':[1],'B':[2]})
它将输出如下所示,这是错误的
错误输出:
pd.concat([df1, df2]).drop_duplicates(keep=False)
Out[655]:
A B
1 2 3
正确的输出
Out[656]:
A B
1 2 3
2 3 4
3 3 4
如何实现这一目标?
方法一:将isin与tuple结合使用
df1[~df1.apply(tuple,1).isin(df2.apply(tuple,1))]
Out[657]:
A B
1 2 3
2 3 4
3 3 4
方法二:与指标合并
df1.merge(df2,indicator = True, how='left').loc[lambda x : x['_merge']!='both']
Out[421]:
A B _merge
1 2 3 left_only
2 3 4 left_only
3 3 4 left_only
也许是一个简单的单行程序,具有相同或不同的列名。即使df2['Name2']包含重复的值也能正常工作。
newDf = df1.set_index('Name1')
.drop(df2['Name2'], errors='ignore')
.reset_index(drop=False)
定义数据框架:
df1 = pd.DataFrame({
'Name':
['John','Mike','Smith','Wale','Marry','Tom','Menda','Bolt','Yuswa'],
'Age':
[23,45,12,34,27,44,28,39,40]
})
df2 = df1[df1.Name.isin(['John','Smith','Wale','Tom','Menda','Yuswa'])
df1
Name Age
0 John 23
1 Mike 45
2 Smith 12
3 Wale 34
4 Marry 27
5 Tom 44
6 Menda 28
7 Bolt 39
8 Yuswa 40
df2
Name Age
0 John 23
2 Smith 12
3 Wale 34
5 Tom 44
6 Menda 28
8 Yuswa 40
两者之间的区别是:
df1[~df1.isin(df2)].dropna()
Name Age
1 Mike 45.0
4 Marry 27.0
7 Bolt 39.0
地点:
isin(df2)返回df1中也在df2中的行。 ~(元素逻辑NOT)在表达式前面对结果求反,因此我们得到df1中不在df2中的元素——两者之间的差值。 .dropna()删除NaN显示所需输出的行
注意:这只适用于len(df1) >= len(df2)。如果df2比df1长,可以反转表达式:df2[~df2.isin(df1)].dropna()