python - linalg - Binarización de matrices numpy usando solo una expresión
numpy python 3 (4)
Numpy trata cada matriz 1d como un vector, matriz 2d como secuencia de vectores (matriz) y la matriz 3d + como un tensor genérico. Esto significa que cuando realizamos operaciones, estamos realizando matemática vectorial. Así que solo puedes hacer:
>>> a = (a > 0.5).astype(np.int_)
Por ejemplo:
>>> 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]])
Lo que sucede aquí es que estás iterando automáticamente a través de cada elemento de cada fila en la matriz 4x4 y aplicando una comparación booleana a cada elemento.
Si> 0.5 devuelve True, si no devuelve False.
Luego, al llamar al método .astype y pasar np.int_ como argumento, le está diciendo a numpy que reemplace todos los valores booleanos con su representación de enteros, en efecto binarizando la matriz según su valor de comparación.
Estoy buscando una forma de binarizar una matriz Nd numpy basada en el umbral usando solo una expresión. Así que tengo algo como esto:
np.random.seed(0)
np.set_printoptions(precision=3)
a = np.random.rand(4, 4)
threshold, upper, lower = 0.5, 1, 0
a es ahora:
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]])
Ahora puedo disparar estas 2 expresiones:
a[a>threshold] = upper
a[a<=threshold] = lower
y lograr lo que quiero:
array([[ 0., 1., 1., 1.],
[ 1., 1., 0., 1.],
[ 0., 1., 0., 1.],
[ 1., 0., 0., 1.]])
¿Pero hay una manera de hacer esto con una sola expresión?
Podemos considerar 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]])
Puede escribir la expresión directamente, esto devolverá una matriz booleana, y se puede usar simplemente como una matriz de entero sin signo de 1 byte ("uint8") para otros cálculos:
print a > 0.5
salida
[[False True True True]
[ True True False True]
[False True False True]
[ True False False True]]
En una línea y con valores superiores / inferiores personalizados, puede escribir, por ejemplo:
upper = 10
lower = 3
treshold = 0.5
print lower + (a>treshold) * (upper-lower)
Un método más corto es simplemente multiplicar la matriz booleana de la condición por 1 o 1.0, según el tipo que desee.
>>> 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.]])