如何在 Python Pandas 中比较包含缺失值的两个 DataFrame
介绍
Pandas 使用 NumPy NaN (np.nan) 对象来表示缺失值。这个 Numpy NaN 值有一些有趣的数学特性。例如,它不等于自身。然而,当与自身比较时,Python None 对象会评估为 True。
操作方法..
让我们看一些例子来了解 np.nan 的行为。
import pandas as pd import numpy as np # Python None Object compared against self. print(f"Output \n *** {None == None} ")
输出
*** True
# Numpy nan compared against self. print(f"Output \n *** {np.nan == np.nan} ")
输出
*** False
# Is nan > 10 or 1000 ? print(f"Output \n *** {np.nan > 10} ")
输出
*** False
传统上,Series 和 DataFrames 使用等于运算符 == 来进行比较。比较的结果是一个对象。让我们首先看看如何使用等于运算符。
# create a dataframe with tennis players and their grandslam titles. df = pd.DataFrame(data={"players": ['Federer', 'Nadal', 'Djokovic', 'Murray','Medvedev','Zverev'], "titles": [20, 19, 17, 3,np.nan,np.nan]}) # set the index df.index = df['players'] # sort the index in ascending df.sort_index(inplace=True, ascending=True) # check if the index is set df.index.is_monotonic_increasing # see records print(f"Output \n{df}")
输出
players titles players Djokovic Djokovic 17.0 Federer Federer 20.0 Medvedev Medvedev NaN Murray Murray 3.0 Nadal Nadal 19.0 Zverev Zverev NaN
1. 为了更好地理解,我们将首先将所有球员与标量值“Federer”进行比较,并查看结果。
print(f'Output \n {df == "Federer"}')
输出
players titles players Djokovic False False Federer True False Medvedev False False Murray False False Nadal False False Zverev False False
C:\Users\sasan\anaconda3\lib\site-packages\pandas\core\ops\array_ops.py:253: FutureWarning: elementwise comparison failed; returning scalar instead, but in the future will perform elementwise comparison res_values = method(rvalues)
2. 这按预期工作,但每当您尝试比较包含缺失值的 DataFrame 时就会出现问题。为了观察这一点,让我们将 df 与自身进行比较。
df_compare = df == df print(f'Output \n {df_compare}')
输出
players titles players Djokovic True True Federer True True Medvedev True False Murray True True Nadal True True Zverev True False
3. 乍一看,所有值似乎都是正确的,正如您所期望的那样。但是,使用 .all 方法查看每列是否仅包含 True 值(因为我们正在比较两个相似的对象,对吧?)会产生意外的结果。
print(f'Output \n {df_compare.all()}')
输出
players True titles False dtype: bool
4. 如前所述,发生这种情况是因为缺失值彼此之间不进行相等比较。看,我们清楚地知道 medvedev 和 Zverev 没有头衔(即 NaN),所以如果我们添加每列中缺失值的数量,我们应该为头衔获得值 2,为球员获得值 0。让我们看看会发生什么。
print(f'Output \n {(df_compare == np.nan).sum()}')
输出
players 0 titles 0 dtype: int64
5. 以上结果出乎意料,因为 nan 的行为非常不同。
6. 将两个完整的 DataFrame 彼此比较的正确方法不是使用等于运算符 (==),而是使用 .equals 方法。
此方法将位于相同位置的 NaN 视为相等。
需要注意的是,.eq 方法等效于 ==,而不是 .equals。
print(f'Output \n {df_compare.equals(df_compare)}')
输出
True
7. 如果您尝试将两个 DataFrame 作为单元测试的一部分进行比较,还有另一种方法。assert_frame_equal 函数如果两个 DataFrame 不相等,则引发 AssertionError。如果两个 DataFrame 相等,则返回 None。
from pandas.testing import assert_frame_equal print(f'Output \n {assert_frame_equal(df_compare, df_compare) is None}')
输出
True