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
これを行うための最も簡潔でPythonicの方法は何ですか?
これを行うより速い(おそらくより簡潔でそして/またはより少ないPythonic)方法はありますか?
これは、人間の頭のMRIスキャンのためのウィンドウ/レベル調整サブルーチンの一部です。 2DのNumpy配列は、画像のピクセルデータです。
これを行うための最速かつ最も簡潔な方法は、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
実際にはarr
where arr < 255
、それ以外の場合は255
という別の配列が必要なので、これは簡単に実行できます。
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
を変更する)、np.minimum
のout
パラメータを使用できます。
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
where
関数を使うことでこれを最も早く達成できると思います。
たとえば、派手な配列で0.2より大きいアイテムを探し、それらを0に置き換えます。
import numpy as np
nums = np.random.Rand(4,3)
print np.where(nums > 0.2, 0, nums)
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
別の方法は、インプレース置換を行い、多次元配列で動作するnp.place
を使用することです。
import numpy as np
arr = np.arange(6).reshape(2, 3)
np.place(arr, arr == 0, -10)
より柔軟にするために、&
、|
(および/または)を使用することもできます。
5から10までの値:A[(A>5)&(A<10)]
10より大きい値または5より小さい値:A[(A<5)|(A>10)]