Pandas df.equals() 在相​​同的数据帧上返回 False?

Pandas df.equals() returning False on identical dataframes?

df_1df_2为:

In [1]: import pandas as pd
   ...: df_1 = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]})
   ...: df_2 = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]})

In [2]: df_1
Out[2]:
   a  b
0  1  4
1  2  5
2  3  6

我们在df_1中添加一行r

In [3]: r = pd.DataFrame({'a': ['x'], 'b': ['y']})
   ...: df_1 = df_1.append(r, ignore_index=True)

In [4]: df_1
Out[4]:
   a  b
0  1  4
1  2  5
2  3  6
3  x  y

我们现在从 df_1 中删除添加的行并再次取回原来的 df_1

In [5]: df_1 = pd.concat([df_1, r]).drop_duplicates(keep=False)

In [6]: df_1
Out[6]:
   a  b
0  1  4
1  2  5
2  3  6

In [7]: df_2
Out[7]:
   a  b
0  1  4
1  2  5
2  3  6

虽然 df_1df_2 相同,但 equals() returns False.

In [8]: df_1.equals(df_2)
Out[8]: False

对 SO 进行了研究,但找不到相关问题。 我做错了什么吗?在这种情况下如何获得正确的结果? (df_1==df_2).all().all() returns True 但不适用于 df_1df_2 长度不同的情况。

这又是一个微妙的发现,干得好。

import pandas as pd
df_1 = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]})
df_2 = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]})
r = pd.DataFrame({'a': ['x'], 'b': ['y']})
df_1 = df_1.append(r, ignore_index=True)
df_1 = pd.concat([df_1, r]).drop_duplicates(keep=False)
df_1.equals(df_2)

from pandas.util.testing import assert_frame_equal
assert_frame_equal(df_1,df_2)

现在我们可以看到断言失败的问题。

AssertionError: Attributes of DataFrame.iloc[:, 0] (column name="a") are different

Attribute "dtype" are different
[left]:  object
[right]: int64

当您将字符串添加到整数时,整数变成了对象。所以这就是为什么 equals 也失败了..

根据 df.equals 文档:

This function allows two Series or DataFrames to be compared against each other to see if they have the same shape and elements. NaNs in the same location are considered equal. The column headers do not need to have the same type, but the elements within the columns must be the same dtype.

因此,只有当元素具有相同的值且 dtypes 也相同时,df.equals 才会 return True

当您从 df_1 添加和删除行时,dtypesint 变为 object,因此它 returns False.

用你的例子解释:

In [1028]: df_1 = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]})

In [1029]: df_2 = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]})

 In [1031]: df_1.dtypes
Out[1031]: 
a    int64
b    int64
dtype: object

In [1032]: df_2.dtypes
Out[1032]: 
a    int64
b    int64
dtype: object

所以,如果你看到上面的内容,两个 dfs 的 dtypes 是相同的,因此下面的条件 returns True:

In [1030]: df_1.equals(df_2)
Out[1030]: True

添加和删除行后:

In [1033]: r = pd.DataFrame({'a': ['x'], 'b': ['y']})

In [1034]: df_1 = df_1.append(r, ignore_index=True)

In [1036]: df_1 = pd.concat([df_1, r]).drop_duplicates(keep=False)

In [1038]: df_1.dtypes
Out[1038]: 
a    object
b    object
dtype: object

dtype 已更改为 object,因此低于条件 returns False:

In [1039]: df_1.equals(df_2)
Out[1039]: False

如果您仍然想要 return True,您需要将 dtypes 改回 int:

In [1042]: df_1 = df_1.astype(int)
In [1044]: df_1.equals(df_2)
Out[1044]: True

使用pandas.testing.assert_frame_equal(df_1, df_2, check_dtype=True),这也会检查数据类型是否相同。

(在这种情况下,当您追加然后删除字符串行时,您的数据类型从 int 更改为 'object'(字符串)。)

AssertionError: Attributes of DataFrame.iloc[:, 0] (column name="a") are different

Attribute "dtype" are different
[left]:  object
[right]: int64

根据其他人的意见,在这种情况下可以这样做:

from pandas.util.testing import assert_frame_equal

identical_df = True
try:
    assert_frame_equal(df_1, df_2, check_dtype=False)
except AssertionError:
    identical_df = False