Замените все элементы массива 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
каков самый лаконичный и питонический способ сделать это?
есть ли более быстрый (возможно, менее сжатый и/или менее питонический) способ сделать это?
Это будет частью подпрограммы настройки окна / уровня для МРТ-сканирования из человеческой головы. Массив 2D numpy - это пиксельные данные изображения.
6 ответов:
Я думаю, что самый быстрый и самый краткий способ сделать это-использовать встроенную индексацию Numpy. Если у вас есть
ndarrayимениarrвы можете заменить все элементы>255со значениемxследующим образом:arr[arr > 255] = xЯ запустил это на своей машине с случайной матрицей 500 x 500, заменив все значения > 0,5 на 5, и это заняло в среднем 7,59 МС.
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здесь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:np.minimum(arr, 255, out=arr)или
np.clip(arr, 0, 255, arr)(the
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вам придется сделать это дважды, что-то вродеnp.minimum(a, 255, a) np.maximum(a, 0, a)или
a[a>255] = 255 a[a<0] = 0
Я думаю, что вы можете достичь этого быстрее всего с помощью
whereфункция:например, поиск элементов больше 0,2 в массиве numpy и замена их на 0:
import numpy as np nums = np.random.rand(4,3) print np.where(nums > 0.2, 0, nums)
можно использовать numpy.надень маску:
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)]
Comments