Двойная матричная бинаризация с использованием только одного выражения

Я ищу способ бинаризации numpy N-d массива на основе порога, используя только одно выражение. Поэтому у меня есть что-то вроде этого:

np.random.seed(0)
np.set_printoptions(precision=3)
a = np.random.rand(4, 4)
threshold, upper, lower = 0.5, 1, 0

a теперь:

array([[ 0.02 ,  0.833,  0.778,  0.87 ],
       [ 0.979,  0.799,  0.461,  0.781],
       [ 0.118,  0.64 ,  0.143,  0.945],
       [ 0.522,  0.415,  0.265,  0.774]])

Теперь я могу запустить эти 2 выражения:

a[a>threshold] = upper
a[a<=threshold] = lower

и достигните того, что я хочу:

array([[ 0.,  1.,  1.,  1.],
       [ 1.,  1.,  0.,  1.],
       [ 0.,  1.,  0.,  1.],
       [ 1.,  0.,  0.,  1.]])

Но есть ли способ сделать это только с одним выражением?

Ответ 1

Мы можем рассмотреть np.where:

np.where(a>threshold, upper, lower)
Out[6]: 
array([[0, 1, 1, 1],
       [1, 1, 0, 1],
       [0, 1, 0, 1],
       [1, 0, 0, 1]])

Ответ 2

Numpy рассматривает каждый 1d-массив как вектор, 2d-массив как последовательность векторов (матрицы) и 3d + array как общий тензор. Это означает, что когда мы выполняем операции, мы выполняем векторную математику. Поэтому вы можете просто сделать:

>>> a = (a > 0.5).astype(np.int_)

Например:

>>> np.random.seed(0)
>>> np.set_printoptions(precision=3)

>>> a = np.random.rand(4, 4)

>>> a
>>> array([[ 0.549,  0.715,  0.603,  0.545],
       [ 0.424,  0.646,  0.438,  0.892],
       [ 0.964,  0.383,  0.792,  0.529],
       [ 0.568,  0.926,  0.071,  0.087]])

>>> a = (a > 0.5).astype(np.int_)  # Where the numpy magic happens.

>>> array([[1, 1, 1, 1],
           [0, 1, 0, 1],
           [1, 0, 1, 1],
           [1, 1, 0, 0]])

Что здесь происходит, так это то, что вы автоматически выполняете итерацию через каждый элемент каждой строки в матрице 4x4 и применяете логическое сравнение с каждым элементом.

If > 0.5 return True, else return False.

Затем, вызывая метод .astype и передавая np.int _ в качестве аргумента, вы говорите numpy, чтобы заменить все логические значения на их целочисленное представление, в действительности бинаризуя матрицу на основе вашего значения сравнения.

Ответ 3

Вы можете напрямую написать выражение, это вернет логический массив и может использоваться просто как 1-байтовый массив без знака ( "uint8" ) для дальнейших вычислений:

print a > 0.5

Выход

[[False  True  True  True]
 [ True  True False  True]
 [False  True False  True]
 [ True False False  True]]

В одной строке и с пользовательскими верхними/нижними значениями вы можете написать так, например:

upper = 10
lower = 3
treshold = 0.5

print lower + (a>treshold) * (upper-lower)

Ответ 4

Более короткий метод заключается в простом умножении булевой матрицы из условия на 1 или 1.0, в зависимости от типа, который вы хотите.

>>> a = np.random.rand(4,4)
>>> a
array([[ 0.63227032,  0.18262573,  0.21241511,  0.95181594],
       [ 0.79215808,  0.63868395,  0.41706148,  0.9153959 ],
       [ 0.41812268,  0.70905987,  0.54946947,  0.51690887],
       [ 0.83693151,  0.10929998,  0.19219377,  0.82919761]])
>>> (a>0.5)*1
array([[1, 0, 0, 1],
       [1, 1, 0, 1],
       [0, 1, 1, 1],
       [1, 0, 0, 1]])
>>> (a>0.5)*1.0
array([[ 1.,  0.,  0.,  1.],
       [ 1.,  1.,  0.,  1.],
       [ 0.,  1.,  1.,  1.],
       [ 1.,  0.,  0.,  1.]])