Pandas“只能比较相同标签的DataFrame对象”错误
- 2025-02-28 08:22:00
- admin 原创
- 93
问题描述:
我正在使用 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 对象。如果前两次比较正常,那么第三次有什么问题?
谢谢
解决方案 1:
这里有一个小例子来演示这一点(它只适用于 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
注意:这仍然会引发(如果排序后索引/列的标签不相同)。
解决方案 2:
如果不需要比较,您也可以尝试删除索引列:
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))
解决方案 3:
当提出这个问题时,Pandas 中没有其他函数可以测试相等性,但是不久前已经添加了它:pandas.equals
你可以像这样使用它:
df1.equals(df2)
一些不同之处==
是:
您没有收到问题中描述的错误
它返回一个简单的布尔值。
同一位置的 NaN 值被视为相等
2 DataFrames 需要具有相同的内容
dtype
才被视为相等,请参阅此 stackoverflow 问题
编辑:正如@paperskilltrees 回答
中指出的那样,索引对齐很重要。除了提供的解决方案之外,另一个选项是在比较 DataFrames 之前对 DataFrames 的索引进行排序。为此,将是。df1
`df1.sort_index(inplace=True)`
解决方案 4:
比较两个 DataFrame 时,必须确保第一个 DataFrame 中的记录数与第二个 DataFrame 中的记录数匹配。在我们的示例中,两个 DataFrame 各有 4 条记录,包含 4 种产品和 4 种价格。
例如,如果其中一个 DataFrame 有 5 种产品,而另一个 DataFrame 有 4 种产品,并且您尝试运行比较,则会收到以下错误:
ValueError:只能比较相同标签的 Series 对象
这应该可行
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/
解决方案 5:
Flyingdutchman 的答案很棒,但错了:它使用DataFrame.equals
,在你的情况下会返回False
。相反,你想使用DataFrame.eq
,它会返回True
。
似乎DataFrame.equals
忽略了数据框的索引,而DataFrame.eq
使用数据框的索引进行对齐,然后比较对齐的值。这是一个引用Pandas 核心陷阱的机会:
需要牢记的基本原则是:数据对齐是内在的。除非您明确地这样做,否则标签和数据之间的链接不会被破坏。
正如我们在以下示例中看到的,除非明确要求,否则数据对齐既不会破坏也不会强制执行。因此,我们有三种不同的情况。
没有给出关于对齐的明确指示:
==
又名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
对齐明显被破坏:
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
明确强制对齐:
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
我的答案是熊猫版本1.0.3
。
PS当您将数据框与自身进行比较时,它会自动对齐,因此我们可能会忘记对齐。这是否意味着上述所有方法都会给您?仅适用于没有True
缺失值的数据框。但是,如果数据框包含缺失值,则会产生,而所有其他方法都会产生。这是因为将两个视为相等,这是非常不寻常的(按照惯例,是)。equals()
`TrueFalse
equals()NaN
np.nan == np.nan`False
解决方案 6:
这里我展示了一个如何处理此错误的完整示例。我添加了包含零的行。您可以从 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
解决方案 7:
我在尝试对数据框列表进行排序时遇到了这个问题。
我尝试根据索引对一些数据框进行排序并将其连接在一起。
例如,我有:
2022 年数据的数据框,索引范围从 2022-01-01 到 2022-12-31
2023 年数据的数据框,索引范围从 2023-01-01 到 2023-12-31
数据框有一个索引,它是一个日期时间对象
在这种情况下,我需要做的是添加一个key
lambda 函数,sorted
如下所示:
df_list_sorted = sorted(df_list, key=lambda df: df.iloc[0].name)
这里的关键点是:提供某种方法来指定如何对数据框进行排序。这应该使用函数key
的参数来完成sorted
,您可以提供(例如)一个 lambda 函数来提取要排序的键。
这在此示例中有效,因为数据框包含有序且不重叠的索引。
您还可以通过以下方式获得相同的结果:
连接数据框
对索引进行就地排序
这对于更复杂的情况有效,其中数据框可能在其索引中重叠,或者索引可能未排序。
但是,它当然会更慢,因为在数据帧连接之后需要进行额外的就地排序。
解决方案 8:
我找到了我案例中错误的来源:
问题是列名列表意外地被包含在另一个列表中。
考虑以下例子:
column_names=['warrior','eat','ok','monkeys']
df_good = pd.DataFrame(np.ones(shape=(6,4)),columns=column_names)
df_good['ok'] < df_good['monkeys']
>>> 0 False
1 False
2 False
3 False
4 False
5 False
df_bad = pd.DataFrame(np.ones(shape=(6,4)),columns=[column_names])
df_bad ['ok'] < df_bad ['monkeys']
>>> ValueError: Can only compare identically-labeled DataFrame objects
问题是你无法从视觉上区分坏的 DataFrame 和好的 DataFrame。
解决方案 9:
就我而言,我只是在创建数据框时直接写入参数列,因为一个 sql 查询中的数据带有名称,而其他查询中没有
扫码咨询,免费领取项目管理大礼包!