web-dev-qa-db-ja.com

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

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配列は、画像のピクセルデータです。

150
NLi10Me

これを行うための最速かつ最も簡潔な方法は、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
260
mdml

実際にはarr where arr < 255、それ以外の場合は255という別の配列が必要なので、これは簡単に実行できます。

result = np.minimum(arr, 255)

より一般的には、下限および/または上限については、

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

255を超える値、またはもっと複雑な値にアクセスしたい場合は、@ mtitan8の回答がより一般的ですが、np.clipnp.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を変更する)、np.minimumoutパラメータを使用できます。

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
40
askewchan

where関数を使うことでこれを最も早く達成できると思います。

たとえば、派手な配列で0.2より大きいアイテムを探し、それらを0に置き換えます。

import numpy as np

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

print np.where(nums > 0.2, 0, nums)
10
Amir F

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
lev

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

import numpy as np

arr = np.arange(6).reshape(2, 3)
np.place(arr, arr == 0, -10)
8
Shital Shah

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

5から10までの値:A[(A>5)&(A<10)]

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

1
Mahdi Shahbaba