ある値より大きいPython NumPy配列のすべての要素を置き換えます


187

2D NumPy配列があり、その中のすべての値をしきい値T以上の255.0に置き換えたいです。私の知る限り、最も基本的な方法は次のとおりです。

shape = arr.shape
result = np.zeros(shape)
for x in range(0, shape[0]):
    for y in range(0, shape[1]):
        if arr[x, y] >= T:
            result[x, y] = 255
  1. これを行うための最も簡潔でpythonicな方法は何ですか?

  2. これを行うためのより高速な(おそらく簡潔さおよび/またはpythonicが少ない)方法はありますか?

これは、人間の頭のMRIスキャンのウィンドウ/レベル調整サブルーチンの一部になります。2D numpy配列は画像のピクセルデータです。


詳細については、このインデックス作成の概要をご覧ください。
askewchan 2013年

回答:


329

これを行うための最速かつ最も簡潔な方法は、NumPyの組み込みのFancyインデックスを使用することだと思います。あなたがいる場合はndarray名前のarr、あなたはすべての要素置き換えることができます>255値とをx次のように:

arr[arr > 255] = x

私はこれを500 x 500のランダムマトリックスを使用して自分のマシンで実行し、> 0.5をすべての値で5に置き換えたところ、平均7.59msかかりました。

In [1]: import numpy as np
In [2]: A = np.random.rand(500, 500)
In [3]: timeit A[A > 0.5] = 5
100 loops, best of 3: 7.59 ms per loop

3
これは、OPのように配列arrを作成するのではなく、既存の配列を変更することに注意してくださいresult
askewchan 2013年

1
変更せずにA新しい配列を作成する方法はありますか?
硝酸ナトリウム2015

n = 2のa [2]、a [4]、a [6]、a [8] .....のように、与えられたnの倍数であるインデックスの値を変更したい場合はどうしますか?
lavee_singh 2015年

100ループ、最高3:2.22 ms /ループ
dreab

5
注:データがpythonリストにある場合、これは機能しませんnp.array([1,2,3]
。numpy

46

実際にはarrwhereである別の配列が必要なのでarr < 255255そうでなければ、これは簡単に行うことができます:

result = np.minimum(arr, 255)

より一般的には、下限および/または上限の場合:

result = np.clip(arr, 0, 255)

255を超える値やもっと複雑な値にアクセスしたいだけの場合は、@ mtitan8の答えがより一般的ですがnp.clip、そしてnp.minimum(またはnp.maximum)はあなたの場合にはより優れており、はるかに高速です:

In [292]: timeit np.minimum(a, 255)
100000 loops, best of 3: 19.6 µs per loop

In [293]: %%timeit
   .....: c = np.copy(a)
   .....: c[a>255] = 255
   .....: 
10000 loops, best of 3: 86.6 µs per loop

これをインプレースで実行する場合(つまり、arrを作成する代わりに変更する場合result)は、次のoutパラメータを使用できますnp.minimum

np.minimum(arr, 255, out=arr)

または

np.clip(arr, 0, 255, arr)

out=引数は関数の定義と同じ順序なので、名前はオプションです。)

インプレース変更の場合、ブールインデックスは大幅に高速化されます(コピーを個別に作成して変更する必要はありません)。ただし、minimum次のように高速ではありません。

In [328]: %%timeit
   .....: a = np.random.randint(0, 300, (100,100))
   .....: np.minimum(a, 255, a)
   .....: 
100000 loops, best of 3: 303 µs per loop

In [329]: %%timeit
   .....: a = np.random.randint(0, 300, (100,100))
   .....: a[a>255] = 255
   .....: 
100000 loops, best of 3: 356 µs per loop

比較のために、最小値と最大値で値を制限したい場合clipは、これを2回行う必要はありません。

np.minimum(a, 255, a)
np.maximum(a, 0, a)

または、

a[a>255] = 255
a[a<0] = 0

1
完全なコメントをありがとうございましたが、np.clipとnp.minimumはこの場合に必要なものではないようです。OPでは、しきい値Tと置換値(255)が必ずしも同じではないことがわかります数。しかし、私はまだ徹底するためにあなたに賛成票を投じました。再度、感謝します。
NLi10Me 2013年

n = 2のa [2]、a [4]、a [6]、a [8] .....のように、与えられたnの倍数であるインデックスの値を変更したい場合はどうしますか?
lavee_singh 2015年

@lavee_singh、これを行うには、スライスの3番目の部分を使用できます。これは通常無視されa[start:stop:step]ます。配列の要素をからstartに与えますstopが、すべての要素の代わりに、すべてのみを受け取りますstep(無視した場合、1デフォルトです) )。したがって、すべての偶数をゼロに設定するには、次のようにしますa[::2] = 0
askewchan

おかげで、単純なリストでそれを知っていたとしても、このようなものが必要でしたが、numpy.arrayでどのように機能するかわかりませんでした。
lavee_singh

14

私はあなたがwhere関数を使用することでこれを最も早く達成できると思います:

たとえば、numpy配列で0.2より大きいアイテムを探し、それらを0で置き換えるには、

import numpy as np

nums = np.random.rand(4,3)

print np.where(nums > 0.2, 0, nums)

10

numpy.putmaskの使用を検討できます。

np.putmask(arr, arr>=T, 255.0)

以下は、Numpyの組み込みインデックスとのパフォーマンス比較です。

In [1]: import numpy as np
In [2]: A = np.random.rand(500, 500)

In [3]: timeit np.putmask(A, A>0.5, 5)
1000 loops, best of 3: 1.34 ms per loop

In [4]: timeit A[A > 0.5] = 5
1000 loops, best of 3: 1.82 ms per loop

8

別の方法はnp.place、インプレース置換を行い、多次元配列で機能するを使用することです。

import numpy as np

# create 2x3 array with numbers 0..5
arr = np.arange(6).reshape(2, 3)

# replace 0 with -10
np.place(arr, arr == 0, -10)

これは私が最初に出会ったため、私が使用したソリューションです。これと上記の選択した回答の間に大きな違いがあるのでしょうか。どう思いますか?
ジョナサン・キング

私の非常に限られたテストでは、np.placeを使用した上記のコードの実行は、承認された回答の直接インデックス作成の方法よりも2倍遅く実行されます。np.placeがより最適化されるだろうと思っていたので、それは驚くべきことですが、おそらく直接のインデックス作成にもっと力を入れていると思います。
Shital Shah

私の場合 np.place、組み込みの方法に比べて速度が遅くなりましたが、このコメントでは反対のことが主張されています。
riyansh.legend

3

さらに柔軟性を高めるために&|(および/または)を使用することもできます。

5〜10の値: A[(A>5)&(A<10)]

10より大きい値または5より小さい値: A[(A<5)|(A>10)]

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