条件が満たされた場合のNumpy要素の交換


94

条件が満たされた場合に各要素が1または0に変更されるように操作する必要がある大きなnumpy配列があります(後でピクセルマスクとして使用されます)。配列には約800万の要素があり、現在の方法では削減パイプラインに時間がかかりすぎます。

for (y,x), value in numpy.ndenumerate(mask_data): 

    if mask_data[y,x]<3: #Good Pixel
        mask_data[y,x]=1
    elif mask_data[y,x]>3: #Bad Pixel
        mask_data[y,x]=0

これをスピードアップするnumpy関数はありますか?


1
もしあなたが何をしたいmask_data[y,x]==3ですか?
DSM

良い点、それはまだ悪いピクセルになります。条件を次のように変更しますif mask_data[y,x]>=3:
ChrisFro 2013年

回答:


128
>>> import numpy as np
>>> a = np.random.randint(0, 5, size=(5, 4))
>>> a
array([[4, 2, 1, 1],
       [3, 0, 1, 2],
       [2, 0, 1, 1],
       [4, 0, 2, 3],
       [0, 0, 0, 2]])
>>> b = a < 3
>>> b
array([[False,  True,  True,  True],
       [False,  True,  True,  True],
       [ True,  True,  True,  True],
       [False,  True,  True, False],
       [ True,  True,  True,  True]], dtype=bool)
>>> 
>>> c = b.astype(int)
>>> c
array([[0, 1, 1, 1],
       [0, 1, 1, 1],
       [1, 1, 1, 1],
       [0, 1, 1, 0],
       [1, 1, 1, 1]])

これは次の方法で短縮できます。

>>> c = (a < 3).astype(int)

2
一部の列を切り取ってから再度割り当てることなく、特定の列でこれを実現するにはどうすればよいですか?たとえば、列[2、3]の要素のみが条件が満たされたときに値を変更する必要がありますが、他の列は条件が満たされたかどうかに関係なく変更されません。
kuixiong

真ですが、0と1の場合のみです。以下のより一般的な回答を参照してください(効率コストで)
borgr

89
>>> a = np.random.randint(0, 5, size=(5, 4))
>>> a
array([[0, 3, 3, 2],
       [4, 1, 1, 2],
       [3, 4, 2, 4],
       [2, 4, 3, 0],
       [1, 2, 3, 4]])
>>> 
>>> a[a > 3] = -101
>>> a
array([[   0,    3,    3,    2],
       [-101,    1,    1,    2],
       [   3, -101,    2, -101],
       [   2, -101,    3,    0],
       [   1,    2,    3, -101]])
>>>

たとえば、ブール配列を使用したインデックス付けを参照してください。


3
素晴らしいもの、ありがとう!変更した値を参照する場合は、のようなものを使用できますa[a > 3] = -101+a[a > 3]
pexmar 2017

1
@pexmarただし、a[a > 3] = -101+a[a > 3]代わりにa[a > 3] += -101実行すると、メモリリークが発生する可能性が高くなります。
Samuel Prevost 2018

1
pexmarが尋ねたように、変更した値をどのように参照しますか?
フアン

34

最速(最も柔軟)な方法は、使用することであるnp.whereマスク(真および偽の値のアレイ)に応じて二つの配列の間で選択しました:

import numpy as np
a = np.random.randint(0, 5, size=(5, 4))
b = np.where(a<3,0,1)
print('a:',a)
print()
print('b:',b)

生成されます:

a: [[1 4 0 1]
 [1 3 2 4]
 [1 0 2 1]
 [3 1 0 0]
 [1 4 0 1]]

b: [[0 1 0 0]
 [0 1 0 1]
 [0 0 0 0]
 [1 0 0 0]
 [0 1 0 0]]

1
私は条件が満たされていない場合は何も交換したくない場合、すなわち唯一の条件が満たされたとき....そのまま元の数を残していない場合は、値を提供して交換する最良の方法だろうか?
アビシェークSengupta

1
3より小さいaのすべての値を置き換え、残りをそのままにするには、a[a<3] = 0
Markus Dutschke

3

このように1つのステップでマスク配列を作成できます

mask_data = input_mask_data < 3

これによりブール配列が作成され、ピクセルマスクとして使用できます。(コードのように)入力配列を変更していませんが、マスクデータを保持するために新しい配列を作成していることに注意してください-この方法で行うことをお勧めします。

>>> input_mask_data = np.random.randint(0, 5, (3, 4))
>>> input_mask_data
array([[1, 3, 4, 0],
       [4, 1, 2, 2],
       [1, 2, 3, 0]])
>>> mask_data = input_mask_data < 3
>>> mask_data
array([[ True, False, False,  True],
       [False,  True,  True,  True],
       [ True,  True, False,  True]], dtype=bool)
>>> 

1
うん。OPが本当に0と1を必要とする場合、彼は.astype(int)またはを使用できます*1が、との配列はTrueそれFalseと同じくらい優れています。
DSM

-4

私はあなたの質問を理解したかどうかはわかりませんが、あなたが書いた場合:

mask_data[:3, :3] = 1
mask_data[3:, 3:] = 0

これにより、xインデックスとyインデックスが3未満のマスクデータのすべての値が1に等しくなり、残りのすべての値が0に等しくなります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.