Замените все элементы массива 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. каков самый лаконичный и питонический способ сделать это?


  2. есть ли более быстрый (возможно, менее сжатый и/или менее питонический) способ сделать это?



Это будет частью подпрограммы настройки окна / уровня для МРТ-сканирования из человеческой головы. Массив 2D numpy - это пиксельные данные изображения.

1346   6  

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

    Ничего не найдено.