2016-08-24 6 views
1

平均を計算したいネットワークと指定されたノードとの間のパス長を含む1次元numpy ndarrayがあります。問題は複雑ですが、実際には2つのノード間にパスが存在しない場合、アルゴリズムはその接続に対して2147483647という値を返します。この値を未処理のままにしておくと、通常の経路長がネットワークの1〜3の間になるため、明らかに平均を膨らませることになります。これに対処する指定された値を無視してnumpyの配列の平均を返します

1つのオプションは、すべての配列のすべての要素をループになるとNaN2147483647を交換し、その後、それはおそらくそれについて行くの最も効率的な方法ではないですが、平均を見つけるためにnumpy.nanmeanを使用します。 2147483647のすべての値を無視してnumpyで平均を計算する方法はありますか?

平均をとる数百万の値を持つ数百万の配列を持つことができますので、平均がどのように見られるかでどのようにパフォーマンスが向上するかは、実際の違いになります。

答えて

3

これに通常のnumpyフィルタを使用しないのはなぜですか?ところで

m = my_array[my_array != 2147483647].mean() 

あなたは本当にスピードをしたい場合は、あなたの全体のアルゴリズム記述は確かに素朴なようで、たくさんによって改善することができます。

ああ、基本的な分布が正常であることを厳密にチェックしているので、平均を計算していると思います。

+0

、これが最も効率的な方法ですので、我々はそうのような実装を持っているでしょうか?私は数百万の値を持つ配列を数百万個まで持つことができますので、パフォーマンスの向上が本当の違いになります。 (私はちょうどそれを指定した編集を行いました) –

+0

そして、あなたは 'nanmean'のことはどうやって正確に動作しますか?そこには:https://github.com/numpy/numpy/blob/master/numpy/lib/nanfunctions.py#L803 NANがたくさんある場合、バージョンがメモリ効率が高くなるという点を除いて、基本的に同じことです。 NANは、配列全体の余分なキャストを引き起こす浮動小数点数に対してのみ定義されることに注意してください。 – JohnW

+1

スピードに関して、まずそれをテストしてください。**これが問題になったら、戻ってください。 – JohnW

1
​​

タイミング

a = np.random.randn(100000) 
a[::10] = 2147483647 

%timeit np.nanmean(np.where(a == 2147483647, np.nan, a)) 
1000 loops, best of 3: 639 µs per loop 

%timeit a[a != 2147483647].mean() 
1000 loops, best of 3: 259 µs per loop 

import pandas as pd 

%timeit pd.Series(a).ne(2147483647).mean() 
1000 loops, best of 3: 493 µs per loop 
+0

これは@JohnWの方法より効率的ですか? –

+1

あなたは結果を見ましたか、あるいはタイミングだけを見ましたか?正しい使用場所は 'np.nanmean(a == ...、np.nan、a)'です。 'nanmean'を使用しない場合、結果は' nan'になります。 – hpaulj

+0

おっと...はい、それを指摘してくれてありがとう。 – Alexander

1

一つの方法は、一度にすべての要素の合計を取得し、無効なものからの寄与を取り除くことであろう。最後に、平均値そのものを有効な要素の数で割る必要があります。

def mean_ignore_num(arr,num): 
    # Get count of invalid ones 
    invc = np.count_nonzero(arr==num) 

    # Get the average value for all numbers and remove contribution from num 
    return (arr.sum() - invc*num)/float(arr.size-invc) 

を確認した結果 - -

In [191]: arr = np.full(10,2147483647).astype(np.int32) 
    ...: arr[1] = 5 
    ...: arr[4] = 4 
    ...: 

In [192]: arr.max() 
Out[192]: 2147483647 

In [193]: arr.sum() # Extends beyond int32 max limit, so no overflow 
Out[193]: 17179869185 

In [194]: arr[arr != 2147483647].mean() 
Out[194]: 4.5 

In [195]: mean_ignore_num(arr,2147483647) 
Out[195]: 4.5 

ランタイムテスト -

In [38]: arr = np.random.randint(0,9,(10000)) 

In [39]: arr[arr != 7].mean() 
Out[39]: 3.6704609489462414 

In [40]: mean_ignore_num(arr,7) 
Out[40]: 3.6704609489462414 

In [41]: %timeit arr[arr != 7].mean() 
10000 loops, best of 3: 102 µs per loop 

In [42]: %timeit mean_ignore_num(arr,7) 
10000 loops, best of 3: 36.6 µs per loop 
+0

「2147483647 = 2 ** 31-1」。配列のデータ型が 'np.int32'の場合、メソッドにオーバーフローの問題がありますか? –

+0

@WarrenWeckesserそれが世話をするように思える、編集された投稿。 – Divakar

+0

次のようになります。 'np.sum()'は、整数配列を「デフォルトのプラットフォーム整数」にアップキャストします。それが 'np.int64'ならば、問題はないはずです。 –

関連する問題