101

我正在使用 Pandas 比较加载到两个数据帧(uat、prod)中的两个文件的输出:...

uat = uat[['Customer Number','Product']]
prod = prod[['Customer Number','Product']]
print uat['Customer Number'] == prod['Customer Number']
print uat['Product'] == prod['Product']
print uat == prod

The first two match exactly:
74357    True
74356    True
Name: Customer Number, dtype: bool
74357    True
74356    True
Name: Product, dtype: bool

对于第三次打印,我收到一个错误:只能比较标记相同的 DataFrame 对象。如果前两个比较好,那么第三个有什么问题?

谢谢

4

6 回答 6

89

这是一个小例子来证明这一点(它只适用于 DataFrames,而不是 Series,直到 Pandas 0.19 它适用于两者):

In [1]: df1 = pd.DataFrame([[1, 2], [3, 4]])

In [2]: df2 = pd.DataFrame([[3, 4], [1, 2]], index=[1, 0])

In [3]: df1 == df2
Exception: Can only compare identically-labeled DataFrame objects

一种解决方案是先对索引进行排序(注意:某些函数需要排序索引):

In [4]: df2.sort_index(inplace=True)

In [5]: df1 == df2
Out[5]: 
      0     1
0  True  True
1  True  True

注意:对列的顺序==也很敏感,因此您可能必须使用:sort_index(axis=1)

In [11]: df1.sort_index().sort_index(axis=1) == df2.sort_index().sort_index(axis=1)
Out[11]: 
      0     1
0  True  True
1  True  True

注意:这仍然可以提高(如果索引/列在排序后没有相同的标签)。

于 2013-08-31T13:53:28.030 回答
42

如果不需要比较,您也可以尝试删除索引列:

print(df1.reset_index(drop=True) == df2.reset_index(drop=True))

我在单元测试中使用了相同的技术,如下所示:

from pandas.util.testing import assert_frame_equal

assert_frame_equal(actual.reset_index(drop=True), expected.reset_index(drop=True))
于 2016-04-28T21:57:54.260 回答
13

在提出这个问题的时候,Pandas 中没有另一个函数来测试相等性,但它是在不久前添加的:pandas.equals

你像这样使用它:

df1.equals(df2)

一些不同之处==是:

  • 您没有收到问题中描述的错误
  • 它返回一个简单的布尔值。
  • 同一位置的 NaN 值被视为相等
  • 2 DataFrames 需要相同dtype才能被视为相等,请参阅此 stackoverflow 问题

编辑:正如@paperskilltrees
中指出的那样,答案索引对齐很重要。除了提供的解决方案之外,另一种选择是在比较 DataFrame 之前对 DataFrame的索引进行排序。因为那将是。df1df1.sort_index(inplace=True)

于 2020-10-16T08:37:45.130 回答
4

比较两个 DataFrame 时,必须确保第一个 DataFrame 中的记录数与第二个 DataFrame 中的记录数匹配。在我们的示例中,两个 DataFrame 中的每一个都有 4 条记录,有 4 种产品和 4 种价格。

例如,如果其中一个 DataFrame 有 5 个产品,而另一个 DataFrame 有 4 个产品,并且您尝试运行比较,则会收到以下错误:

ValueError:只能比较标签相同的系列对象

这应该工作

import pandas as pd
import numpy as np

firstProductSet = {'Product1': ['Computer','Phone','Printer','Desk'],
                   'Price1': [1200,800,200,350]
                   }
df1 = pd.DataFrame(firstProductSet,columns= ['Product1', 'Price1'])


secondProductSet = {'Product2': ['Computer','Phone','Printer','Desk'],
                    'Price2': [900,800,300,350]
                    }
df2 = pd.DataFrame(secondProductSet,columns= ['Product2', 'Price2'])


df1['Price2'] = df2['Price2'] #add the Price2 column from df2 to df1

df1['pricesMatch?'] = np.where(df1['Price1'] == df2['Price2'], 'True', 'False')  #create new column in df1 to check if prices match
df1['priceDiff?'] = np.where(df1['Price1'] == df2['Price2'], 0, df1['Price1'] - df2['Price2']) #create new column in df1 for price diff 
print (df1)

来自https://datatofish.com/compare-values-dataframes/的示例

于 2020-12-09T11:33:06.510 回答
1

Flyingdutchman 的回答很好但错误它使用DataFrame.equals,这将False在您的情况下返回。相反,您想使用DataFrame.eq,这将返回True

似乎DataFrame.equals忽略了数据框的索引,而DataFrame.eq使用数据框的索引进行对齐,然后比较对齐的值。这是一个引用Pandas 核心问题的场合:

这是一个需要牢记的基本原则:数据对齐是内在的。除非您明确这样做,否则标签和数据之间的链接不会中断。

正如我们在以下示例中所见,除非明确要求,否则数据对齐既不会破坏也不会强制执行。所以我们有三种不同的情况。

  1. 没有给出关于对齐的明确说明:==又名DataFrame.__eq__

   In [1]: import pandas as pd
   In [2]: df1 = pd.DataFrame(index=[0, 1, 2], data={'col1':list('abc')})
   In [3]: df2 = pd.DataFrame(index=[2, 0, 1], data={'col1':list('cab')})
   In [4]: df1 == df2
   ---------------------------------------------------------------------------
   ...
   ValueError: Can only compare identically-labeled DataFrame objects

  1. 对齐被明确破坏:DataFrame.equals, DataFrame.values, DataFrame.reset_index(),
    In [5]: df1.equals(df2)
    Out[5]: False

    In [9]: df1.values == df2.values
    Out[9]: 
    array([[False],
           [False],
           [False]])

    In [10]: (df1.values == df2.values).all().all()
    Out[10]: False

  1. 对齐是明确强制执行的:DataFrame.eq, DataFrame.sort_index(),

    In [6]: df1.eq(df2)
    Out[6]: 
       col1
    0  True
    1  True
    2  True

    In [8]: df1.eq(df2).all().all()
    Out[8]: True
    

我的答案是 pandas 版本1.0.3

于 2022-01-31T08:07:08.593 回答
0

在这里,我将展示如何处理此错误的完整示例。我添加了带零的行。您可以从 csv 或任何其他来源获取数据框。

import pandas as pd
import numpy as np


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

# df2 with 8 rows
df2 = pd.DataFrame({'Name':['John','Mike','Wale','Marry','Tom','Menda','Bolt','Yuswa',],
    'Age':[25,45,14,34,26,44,29,42]})


# get lengths of df1 and df2
df1_len = len(df1)
df2_len = len(df2)


diff = df1_len - df2_len

rows_to_be_added1 = rows_to_be_added2 = 0
# rows_to_be_added1 = np.zeros(diff)

if diff < 0:
    rows_to_be_added1 = abs(diff)
else:
    rows_to_be_added2 = diff
    
# add empty rows to df1
if rows_to_be_added1 > 0:
    df1 = df1.append(pd.DataFrame(np.zeros((rows_to_be_added1,len(df1.columns))),columns=df1.columns))

# add empty rows to df2
if rows_to_be_added2 > 0:
    df2 = df2.append(pd.DataFrame(np.zeros((rows_to_be_added2,len(df2.columns))),columns=df2.columns))

# at this point we have two dataframes with the same number of rows, and maybe different indexes
# drop the indexes of both, so we can compare the dataframes and other operations like update etc.
df2.reset_index(drop=True, inplace=True)
df1.reset_index(drop=True, inplace=True)

# add a new column to df1
df1['New_age'] = None

# compare the Age column of df1 and df2, and update the New_age column of df1 with the Age column of df2 if they match, else None
df1['New_age'] = np.where(df1['Age'] == df2['Age'], df2['Age'], None)

# drop rows where Name is 0.0
df2 = df2.drop(df2[df2['Name'] == 0.0].index)

# now we don't get the error ValueError: Can only compare identically-labeled Series objects
于 2022-02-04T18:43:36.373 回答