web-dev-qa-db-ja.com

Pandas NaNsの等値比較を使用したDataFrames

いくつかの機能を単体テストするコンテキストでは、python pandasを使用して2つのDataFramesの等価性を確立しようとしています。

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

expectの位置を含むdfの全体に対してNaNの全体をテストしようとしているので、何が間違っていますか?

NaNsを含むシリーズ/データフレームの等価性を比較する最も簡単な方法は何ですか?

25
Steve Pike

(インデックス/列名をチェックしないように)check_names = Falseでassert_frame_equalsを使用できます。これらは等しくない場合に発生します。

In [11]: from pandas.testing import assert_frame_equal

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

次のような関数でこれをラップできます。

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

最近ではpandasこの機能は .equals

df.equals(expected)
26
Andy Hayden

NaNのプロパティの1つは、NaN != NaNTrueです。

numexprを使用してこれを行う素敵な方法については、 この回答 を確認してください。

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

これは(擬似コードで)言います:

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

したがって、abに等しいか、abNaNです。

小さなフレームがある場合は、assert_frame_equalは大丈夫です。ただし、大きなフレーム(1,000万行)の場合assert_frame_equalはほとんど役に立ちません。私はそれを中断しなければならなかった、それはとても時間がかかっていた。

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

2つのtimeitsが等しいかどうかを示す(おそらく)望ましい単一のboolDataFrame

In [9]: timeit ((df == df2) | ((df != df) & (df2 != df2))).values.all()
1 loops, best of 3: 687 ms per loop
16
Phillip Cloud

@PhillipCloudの回答に似ていますが、より多くの記述があります

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

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

彼らは本当に同等です

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

Df1に存在しないdf2のnan

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

フレームにないことがわかっている値を入力することもできます

In [38]: df1.fillna(-999) == df1.fillna(-999)
Out[38]: 
      0     1
0  True  True
1  True  True
3
Jeff
_df.fillna(0) == df2.fillna(0)
_

fillna()を使用できます。 ここにドキュメント

_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
stephentgrammer

==とnp.NaNを使用した等値比較はFalse、np.NaN == np.NaNでもFalseです。

単に、「NULL」が元のデータの値でない場合は、df1.fillna('NULL') == df2.fillna('NULL')

安全のために、次のことを行ってください。

例a)2つのデータフレームをNaN値と比較する

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

例b)df2に一致しないdf1の行をフィルター処理する

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

(注:これは間違っています-bools [pd.isnull(df1)== pd.isnull(df2)] = False)

0
Lydia