Pandas DataFrames avec comparaison de L'égalité NaNs

Dans le cadre de l'unité de tester certaines fonctions, je suis en train d'établir l'égalité de 2 DataFrames à l'aide de python pandas:

ipdb> expect
                            1   2
2012-01-01 00:00:00+00:00 NaN   3
2013-05-14 12:00:00+00:00   3 NaN

ipdb> df
identifier                  1   2
timestamp
2012-01-01 00:00:00+00:00 NaN   3
2013-05-14 12:00:00+00:00   3 NaN

ipdb> df[1][0]
nan

ipdb> df[1][0], expect[1][0]
(nan, nan)

ipdb> df[1][0] == expect[1][0]
False

ipdb> df[1][1] == expect[1][1]
True

ipdb> type(df[1][0])
<type 'numpy.float64'>

ipdb> type(expect[1][0])
<type 'numpy.float64'>

ipdb> (list(df[1]), list(expect[1]))
([nan, 3.0], [nan, 3.0])

ipdb> df1, df2 = (list(df[1]), list(expect[1])) ;; df1 == df2
False

etant Donné que je suis en train de tester l'ensemble des expect contre la totalité de dfNaN postes, ce que je fais mal?

Quelle est la façon la plus simple de comparer l'égalité des séries/DataFrames incluant NaN s?

17
demandé sur Steve Pike 2013-10-11 20:03:07

5 réponses

vous pouvez utiliser assert_frame_equals avec check_names=False (afin de ne pas vérifier les noms des index/colonnes), qui s'élèvera s'ils ne sont pas égaux:

In [11]: from pandas.util.testing import assert_frame_equal

In [12]: assert_frame_equal(df, expected, check_names=False)

Vous pouvez envelopper ce dans une fonction avec quelque chose comme:

try:
    assert_frame_equal(df, expected, check_names=False)
    return True
except AssertionError:
    return False

dans les pandas plus récents cette fonctionnalité a été ajoutée comme .equals:

df.equals(expected)
18
répondu Andy Hayden 2015-10-19 21:43:29

Une des propriétés de NaN que NaN != NaNTrue.

découvrez cette réponse pour une belle façon de le faire à l'aide de numexpr.

(a == b) | ((a != a) & (b != b))

dit (en pseudo-code):

a == b or (isnan(a) and isnan(b))

a égale b, ou les deux a et bNaN.

Si vous avez de petits cadres, puis assert_frame_equal va être correct. Toutefois, pour les cadres de grande taille (rangées de 10M)assert_frame_equal est assez inutile. J'ai eu à l'interrompre, c'était aussi long.

In [1]: df = DataFrame(rand(1e7, 15))

In [2]: df = df[df > 0.5]

In [3]: df2 = df.copy()

In [4]: df
Out[4]:
<class 'pandas.core.frame.DataFrame'>
Int64Index: 10000000 entries, 0 to 9999999
Columns: 15 entries, 0 to 14
dtypes: float64(15)

In [5]: timeit (df == df2) | ((df != df) & (df2 != df2))
1 loops, best of 3: 598 ms per loop

timeit de l' (probablement) souhaitée unique bool indiquant si les deux DataFrames sont égaux:

In [9]: timeit ((df == df2) | ((df != df) & (df2 != df2))).values.all()
1 loops, best of 3: 687 ms per loop
12
répondu Phillip Cloud 2017-05-23 11:47:27

Comme @PhillipCloud réponse, mais plus écrit

In [26]: df1 = DataFrame([[np.nan,1],[2,np.nan]])

In [27]: df2 = df1.copy()

Ils sont vraiment équivalent

In [28]: result = df1 == df2

In [29]: result[pd.isnull(df1) == pd.isnull(df2)] = True

In [30]: result
Out[30]: 
      0     1
0  True  True
1  True  True

nan en df2 qui n'existe pas dans df1

In [31]: df2 = DataFrame([[np.nan,1],[np.nan,np.nan]])

In [32]: result = df1 == df2

In [33]: result[pd.isnull(df1) == pd.isnull(df2)] = True

In [34]: result
Out[34]: 
       0     1
0   True  True
1  False  True

Vous pouvez également remplir avec une valeur que vous savez ne pas être dans l'image

In [38]: df1.fillna(-999) == df1.fillna(-999)
Out[38]: 
      0     1
0  True  True
1  True  True
3
répondu Jeff 2013-10-11 16:19:12
df.fillna(0) == df2.fillna(0)

Vous pouvez utiliser fillna(). Documenation ici.

from pandas import DataFrame

# create a dataframe with NaNs
df = DataFrame([{'a': 1, 'b': 2}, {'a': 5, 'b': 10, 'c': 20}])
df2 = df

# comparison fails!
print df == df2

# all is well 
print df.fillna(0) == df2.fillna(0)
1
répondu stephentgrammer 2015-10-01 18:08:20

Toute comparaison d'égalité avec == np.NaN est fausse, même np.NaN = = np.NaN est fausse.

Simplement df1.fillna('NULL') == df2.fillna('NULL'), si 'NULL' n'est pas une valeur dans les données originales.

Pour être sûr, procédez de la manière suivante:

exemple A) comparez deux images de données avec les valeurs de NaN

bools = (df1 == df2)
bools[pd.isnull(df1) & pd.isnull(df2)] = True
assert bools.all().all()

exemple b) filtrer les lignes de df1 qui ne correspondent pas à df2

bools = (df1 != df2)
bools[pd.isnull(df1) & pd.isnull(df2)] = False
df_outlier = df1[bools.all(axis=1)]

(Note: c'est faux - bool[pd.isnull (df1) = = pd.isnull (df2)] = False)

0
répondu Lydia 2015-11-23 19:22:54