2016-09-28 1 views
3

私はランダムな浮動小数点数の配列を持っており、同じ値を別の順序で持つ別の浮動小数点数と比較する必要があります。そのことについては、和、積(とテーブルの次元、したがって必要な方程式の数に応じた他の組み合わせ)を使用します。浮動小数点NumPy配列を使った比較演算と関連演算

しかし、配列の合計(または積)を値の順序に応じて実行すると、精度の問題が発生しました。

import numpy as np 

n = 10 
m = 4 

tag = np.random.rand(n, m) 

s1 = np.sum(tag, axis=1) 
s2 = np.sum(tag[:, ::-1], axis=1) 

# print the number of times s1 is not equal to s2 (should be 0) 
print np.nonzero(s1 != s2)[0].shape[0] 

あなたはそれが時々s1s2が等しくないと貴様がコンピュータ精度の大きさであることを示しています。このコードを実行した場合:ここで

は、この問題を説明するための簡単なスタンドアロンの一例です。

問題が

は、この問題を回避する方法はあります...私は、私は本当に寛容性を与えることができない np.in1dのような機能のものを使用する必要がありますか?

+0

浮動小数点演算が正確であるとは決して想像できません。いくつかのエラーに対応するようにアルゴリズムを変更する必要があります。それ以外の場合は、 'statistics'モジュールにいくつかの魅力的な合計がありますが、それは今のところポイントではありません。特にベクトル化が基本的なツールでなければならないnumpyでは、決して算術演算の順序に頼ることはできません。 –

+0

どうやって 'np.in1d'を使っていますか?リストされたコードについては、 'np.isclose(s1、s2)'を使うことができます。 – Divakar

+0

@Divakar例では使っていませんが、私の実際のアルゴリズムでは、 '' np.in1d(s1、s2) ''や、製品などの他の操作で得られた等価な配列を使用します... –

答えて

4

記載されているコードの場合、np.iscloseを使用できます。許容値も指定できます。

提供されたサンプルを使用して、のは、それを使用することができる方法を見てみましょう -

In [201]: n = 10 
    ...: m = 4 
    ...: 
    ...: tag = np.random.rand(n, m) 
    ...: 
    ...: s1 = np.sum(tag, axis=1) 
    ...: s2 = np.sum(tag[:, ::-1], axis=1) 
    ...: 

In [202]: np.nonzero(s1 != s2)[0].shape[0] 
Out[202]: 4 

In [203]: (~np.isclose(s1,s2)).sum() # So, all matches! 
Out[203]: 0 

は、他のシナリオで許容値を利用するために、我々は、ケースバイケースで作業する必要があります。したがって、np.in1dのような要素単位の比較を含む実装では、broadcastingを入力して、2番目の要素のすべての要素に対して最初の入力のすべての要素の等価性チェックを行うことができます。次に、np.absを使用して「近似係数」を取得し、最後に入力許容値と比較して一致を判断します。 np.in1dをシミュレートするために必要に応じて、軸の1つに沿って何らかの操作を行います。したがって、broadcastingを使用して公差np.in1dがそうのように実装することができ -

def in1d_with_tolerance(A,B,tol=1e-05): 
    return (np.abs(A[:,None] - B) < tol).any(1) 

をOPのコメントで示唆したように、我々はまた、それらをスケールアップした後、浮動ptの数字を丸めることができ、これは必要なものとして、メモリ効率的でなければなりません大規模な配列を扱うためのものです。サンプル実行

def in1d_with_tolerance_v2(A,B,tol=1e-05): 
    S = round(1/tol) 
    return np.in1d(np.around(A*S).astype(int),np.around(B*S).astype(int)) 

- - だから、修正されたバージョンはそうのようになる

In [372]: A = np.random.rand(5) 
    ...: B = np.random.rand(7) 
    ...: B[3] = A[1] + 0.0000008 
    ...: B[6] = A[4] - 0.0000007 
    ...: 

In [373]: np.in1d(A,B) # Not the result we want! 
Out[373]: array([False, False, False, False, False], dtype=bool) 

In [374]: in1d_with_tolerance(A,B) 
Out[374]: array([False, True, False, False, True], dtype=bool) 

In [375]: in1d_with_tolerance_v2(A,B) 
Out[375]: array([False, True, False, False, True], dtype=bool) 

最後に、それは他の実装とユースケースのために働くようにする方法に - それは実装自体に依存するであろう。しかし、ほとんどの場合、np.isclosebroadcastingが役立ちます。

+0

許容範囲を持つin1dのこの実装は、(大きな配列に対して)もっと多くのメモリを使用します...代わりに、浮動小数点精度に近いいくつかの小数と比較したい配列の '' np.around''を代わりに行いましたそれは仕事をしているようだ。ありがとうございました。 –

+0

@thomleo良い点!投稿にそれを追加して、大丈夫だと思っています。 – Divakar

関連する問題