21

NaN を互いに等しいものとして扱う (ただし、NaN 以外のものとは等しくない) 2 つの NumPy 配列を比較する慣用的な方法はあります

たとえば、次の 2 つの配列を比較して等しいとします。

np.array([1.0, np.NAN, 2.0])
np.array([1.0, np.NAN, 2.0])

および次の 2 つの配列が等しくないことを比較します。

np.array([1.0, np.NAN, 2.0])
np.array([1.0, 0.0, 2.0])

スカラーブール結果を生成するメソッドを探しています。

次のようにします。

np.all((a == b) | (np.isnan(a) & np.isnan(b)))

しかし、それは扱いにくく、これらすべての中間配列を作成します。

目に優しく、メモリをより有効に活用する方法はありますか?

PSそれが役立つ場合、配列は同じ形状とdtypeを持つことが知られています。

4

4 に答える 4

17

メモリの使用を本当に気にしている場合 (たとえば、非常に大きな配列がある場合)、numexpr を使用する必要があり、次の式が機能します。

np.all(numexpr.evaluate('(a==b)|((a!=a)&(b!=b))'))

長さ 3e8 の非常に大きな配列でテストしましたが、コードは私のマシンで

np.all(a==b)

同じ量のメモリを使用します

于 2012-05-30T17:29:18.967 に答える
8

免責事項: 私はこれを通常の使用にはお勧めしません。

配列の形状と dtype が同じ場合は、低レベルの使用を検討できますmemoryview

>>> import numpy as np
>>> 
>>> a0 = np.array([1.0, np.NAN, 2.0])
>>> ac = a0 * (1+0j)
>>> b0 = np.array([1.0, np.NAN, 2.0])
>>> b1 = np.array([1.0, np.NAN, 2.0, np.NAN])
>>> c0 = np.array([1.0, 0.0, 2.0])
>>> 
>>> memoryview(a0)
<memory at 0x85ba1bc>
>>> memoryview(a0) == memoryview(a0)
True
>>> memoryview(a0) == memoryview(ac) # equal but different dtype
False
>>> memoryview(a0) == memoryview(b0) # hooray!
True
>>> memoryview(a0) == memoryview(b1)
False
>>> memoryview(a0) == memoryview(c0)
False

ただし、次のような微妙な問題には注意してください。

>>> zp = np.array([0.0])
>>> zm = -1*zp
>>> zp
array([ 0.])
>>> zm
array([-0.])
>>> zp == zm
array([ True], dtype=bool)
>>> memoryview(zp) == memoryview(zm)
False

これは、比較すると等しいにもかかわらず、バイナリ表現が異なるために発生します(もちろん、そうする必要があります。負の符号を出力することを知っている方法です)

>>> memoryview(zp)[0]
'\x00\x00\x00\x00\x00\x00\x00\x00'
>>> memoryview(zm)[0]
'\x00\x00\x00\x00\x00\x00\x00\x80'

明るい面では、期待どおりに短絡します。

In [47]: a0 = np.arange(10**7)*1.0
In [48]: a0[-1] = np.NAN    
In [49]: b0 = np.arange(10**7)*1.0    
In [50]: b0[-1] = np.NAN     
In [51]: timeit memoryview(a0) == memoryview(b0)
10 loops, best of 3: 31.7 ms per loop
In [52]: c0 = np.arange(10**7)*1.0    
In [53]: c0[0] = np.NAN   
In [54]: d0 = np.arange(10**7)*1.0    
In [55]: d0[0] = 0.0    
In [56]: timeit memoryview(c0) == memoryview(d0)
100000 loops, best of 3: 2.51 us per loop

比較のために:

In [57]: timeit np.all((a0 == b0) | (np.isnan(a0) & np.isnan(b0)))
1 loops, best of 3: 296 ms per loop
In [58]: timeit np.all((c0 == d0) | (np.isnan(c0) & np.isnan(d0)))
1 loops, best of 3: 284 ms per loop
于 2012-05-30T17:18:02.927 に答える
0

これがより良いかどうかはわかりませんが、考えてみてください...

import numpy
class FloatOrNaN(numpy.float_):
    def __eq__(self, other):
        return (numpy.isnan(self) and numpy.isnan(other)) or super(FloatOrNaN,self).__eq__(other)

a = [1., np.nan, 2.]
one = numpy.array([FloatOrNaN(val) for val in a], dtype=object)
two = numpy.array([FloatOrNaN(val) for val in a], dtype=object)
print one == two   # yields  array([ True,  True,  True], dtype=bool)

これは、c の代わりに内部の動作を python にすることを犠牲にして、醜さを dtype に押し込みます (Cython/etc はこれを修正します)。ただし、メモリ コストは大幅に削減されます。

まだちょっと醜いけど:(

于 2012-05-30T16:42:44.097 に答える