2017-02-06 12 views
2

異なるサイズの2つの1次元配列XとYがあります。異なるサイズの配列Yを持つ条件に基づくnumpyマスク配列X

X=np.array([0.3, 2.1, 4.3]) 
Y=np.array([1.5, 3.5]) 
mask = X>Y[:,np.newaxis] 

をし、その上例えばにつながるように、今私は、X[mask]=X[mask]+1似た何かを実行したいと思います:私は、例えばXとYの条件から生じた2次元の配列を作成しようとしています:

newX = np.array([0.3, 3.1, 5.3],[0.3, 2.1, 5.3]]) 

私が行うことで、この結果を得ることができた:

newX = np.append(X, X).reshape(2,3) 
newX[mask]=newX[mask]+1 

しかし、これはY配列(例2)の長さをハードコードし、そしてどのnp.appendとコピーが含まれX ad Yが実際に大きな配列である場合(そしてそれはおそらくかなり醜い)、コストがかかる。これを行う正しい方法はありますか?つまり、ブール値を数値コンテキストでint型として扱われます - あなたはmaskがTrueでどこ1を追加したい、この特定のケースでは、 おそらく最も簡単な方法は、放送を利用して プロモーションをDTYPEする

+0

私はちょうど "enter"を押した直後にnp.outerを呼び出したので、少なくともこれはハードコードを取り除きます: 'newX = np.outer(np.ones_like(Y)、X)'しかし、私はまだ分かりませんこれを行うのが最も効率的で正しい方法です。 –

答えて

1

です。

In [49]: X + mask 
Out[49]: 
array([[ 0.3, 3.1, 5.3], 
     [ 0.3, 2.1, 5.3]]) 

可能であれば、明示的にタイル状のコピーXの代わりにブロードキャストを使用してください。 はしかし、あなたがnewXが必要な場合は

In [54]: np.tile(X, (Y.size,1)) 
Out[54]: 
array([[ 0.3, 2.1, 4.3], 
     [ 0.3, 2.1, 4.3]]) 

np.tileを使用することができますので、それは、この目的のために高速であるnp.outerによって行わ乗算を避けることができます。

例えば

、この設定で:

import numpy as np 
import timeit 
import collections 
import matplotlib.pyplot as plt 

timing = collections.defaultdict(list) 
Ns = np.linspace(10, 10000, 5).astype(int) 
Ms = np.linspace(10, 10000, 5).astype(int) 

for N, M in zip(Ns, Ms): 
    X = np.random.random(N) 
    Y = np.random.random(M) 
    timing['tile'].append(timeit.timeit(
     'np.tile(X, (Y.size,1))', 
     'from __main__ import np, X, Y', 
     number=10)) 
    timing['outer'].append(timeit.timeit(
     'np.outer(np.ones_like(Y),X)', 
     'from __main__ import np, X, Y', 
     number=10)) 


plt.plot(Ns*Ms, timing['tile'], label='tile') 
plt.plot(Ns*Ms, timing['outer'], label='outer') 
plt.legend(loc='best') 
plt.show() 

enter image description here

アレイのサイズが大きくなるにつれ、tileouter との差が総時間と比較して減少させるべきです RAM /スワップで大規模な配列を割り当てる/管理するために必要な時間が相対的にsmを圧倒するためすべて 計算コスト。

+0

ありがとう! "1を加える"について、あなたのことはいいトリックですが、これは実際にはstackoverflowの例のためだけだった、私の本当の問題は条件が満たされたときにもっと複雑な計算をします。面白いことに、面白いことに、タイリング値を1ではなく1に設定すると間違いなく2倍遅くなります(タイプ割り振りのオーバーヘッドはどうでしょうか?)、わずかに遅くなります(テストで19.5秒に対して20.5秒%timeit run)を返します。したがって、乗算を実行しないことの利益は、少なくともこのテストの実行では表示されません....構文的にnp.tileはより良いですが、それでも改善です! –

+0

'np.tile'が20秒以上かかる場合、私はあなたに巨大な配列を扱わなければならないと考えています。配列がRAMに完全に収まらない場合、OSはスワップ領域を使用して残りの領域に対応します。 RAMの内外へのアレイの移動は遅く、なぜ 'np.tile'と' np.outer'が長引くのか説明するかもしれません。修正は、より多くのRAMを獲得するか、(おそらく)ブロックで計算を行うなど、あまりメモリを必要としないより巧妙なアルゴリズムを考案することです。 – unutbu

+0

Btw、私はあなたが "... 1の代わりに1にタイル値を設定する間違いをした場合、2倍遅くなる"という意味を理解していませんか? – unutbu

関連する問題