作为单元测试的一部分,我需要测试两个DataFrames是否相等。 DataFrame中列的顺序对我来说并不重要。然而,对熊猫来说似乎很重要:
import pandas
df1 = pandas.DataFrame(index = [1,2,3,4])
df2 = pandas.DataFrame(index = [1,2,3,4])
df1['A'] = [1,2,3,4]
df1['B'] = [2,3,4,5]
df2['B'] = [2,3,4,5]
df2['A'] = [1,2,3,4]
df1 == df2
结果:
Exception: Can only compare identically-labeled DataFrame objects
我相信表达式df1 == df2
应该评估为包含所有True
值的DataFrame。显然,在这种情况下,==
的正确功能应该是有争议的。我的问题是:是否有一个Pandas方法可以满足我的需求?也就是说,有没有办法进行忽略列顺序的相等比较?
答案 0 :(得分:30)
最常见的意图是这样处理:
def assertFrameEqual(df1, df2, **kwds ):
""" Assert that two dataframes are equal, ignoring ordering of columns"""
from pandas.util.testing import assert_frame_equal
return assert_frame_equal(df1.sort_index(axis=1), df2.sort_index(axis=1), check_names=True, **kwds )
当然,请参阅pandas.util.testing.assert_frame_equal
了解您可以传递的其他参数
答案 1 :(得分:10)
您可以使用sort_index
对列进行排序:
df1.sort_index(axis=1) == df2.sort_index(axis=1)
这将评估所有True
值的数据框。
由于@osa评论这对于NaN来说是失败的,并且也不是特别强大,实际上可能建议使用类似于@ quant的答案(注意:如果有问题,我们想要一个bool而不是加注):
def my_equal(df1, df2):
from pandas.util.testing import assert_frame_equal
try:
assert_frame_equal(df1.sort_index(axis=1), df2.sort_index(axis=1), check_names=True)
return True
except (AssertionError, ValueError, TypeError): perhaps something else?
return False
答案 2 :(得分:5)
def equal( df1, df2 ):
""" Check if two DataFrames are equal, ignoring nans """
return df1.fillna(1).sort_index(axis=1).eq(df2.fillna(1).sort_index(axis=1)).all().all()
答案 3 :(得分:4)
通常你会想要快速测试,并且排序方法对于较大的索引可能是非常低效的(例如,如果你使用行而不是列来解决这个问题)。排序方法也容易受到非唯一索引的漏报。
幸运的是,pandas.util.testing.assert_frame_equal
已经使用check_like
选项进行了更新。将此设置为true,测试中不会考虑排序。
使用非唯一索引,您将获得神秘的ValueError: cannot reindex from a duplicate axis
。这是由引擎盖reindex_like
操作引发的,该操作重新排列其中一个DataFrame以匹配其他订单。重新索引比分类更快 ,如下所示。
import pandas as pd
from pandas.util.testing import assert_frame_equal
df = pd.DataFrame(np.arange(1e6))
df1 = df.sample(frac=1, random_state=42)
df2 = df.sample(frac=1, random_state=43)
%timeit -n 1 -r 5 assert_frame_equal(df1.sort_index(), df2.sort_index())
## 5.73 s ± 329 ms per loop (mean ± std. dev. of 5 runs, 1 loop each)
%timeit -n 1 -r 5 assert_frame_equal(df1, df2, check_like=True)
## 1.04 s ± 237 ms per loop (mean ± std. dev. of 5 runs, 1 loop each)
对于那些喜欢性能比较好的人来说:
答案 4 :(得分:1)
排序列仅在行和列标签跨帧匹配时有效。比如,您有2个数据帧在单元格中具有相同的值但具有不同的标签,那么排序解决方案将不起作用。我在使用pandas实现k模式聚类时遇到了这种情况。
我用一个简单的equals函数来检查细胞相等性(下面的代码)
def frames_equal(df1,df2) :
if not isinstance(df1,DataFrame) or not isinstance(df2,DataFrame) :
raise Exception(
"dataframes should be an instance of pandas.DataFrame")
if df1.shape != df2.shape:
return False
num_rows,num_cols = df1.shape
for i in range(num_rows):
match = sum(df1.iloc[i] == df2.iloc[i])
if match != num_cols :
return False
return True
答案 5 :(得分:1)
http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.equals.html
答案 6 :(得分:1)
可能您需要函数来比较忽略了行和列顺序的DataFrame?唯一的要求就是要有一些唯一的列来用作索引。
f1 = pd.DataFrame([
{"id": 1, "foo": "1", "bar": None},
{"id": 2, "foo": "2", "bar": 2},
{"id": 3, "foo": "3", "bar": 3},
{"id": 4, "foo": "4", "bar": 4}
])
f2 = pd.DataFrame([
{"id": 3, "foo": "3", "bar": 3},
{"id": 1, "bar": None, "foo": "1",},
{"id": 2, "foo": "2", "bar": 2},
{"id": 4, "foo": "4", "bar": 4}
])
def comparable(df, index_col='id'):
return df.fillna(value=0).set_index(index_col).to_dict('index')
comparable(f1) == comparable (f2) # returns True
答案 7 :(得分:0)
在处理包含python对象(例如元组和列表df.eq(df2)
和df == df2
)的数据框时,这是不够的。即使每个数据帧中的相同单元格包含相同的对象,例如(0, 0)
,相等比较也将得出False
。要解决此问题,请在比较之前将所有列转换为字符串:
df.apply(lambda x: x.astype(str)).eq(df2.apply(lambda x: x.astype(str)))