python - tutorial - obteniendo la diagonal opuesta de una matriz numpy
transpuesta de una matriz en python numpy (3)
Así que en matrices numpy hay una función incorporada para obtener los índices diagonales, pero parece que no puedo encontrar la forma de obtener la diagonal comenzando desde la parte superior derecha en lugar de la superior izquierda.
Este es el código normal para comenzar desde la parte superior izquierda:
>>> import numpy as np
>>> array = np.arange(25).reshape(5,5)
>>> diagonal = np.diag_indices(5)
>>> array
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24]])
>>> array[diagonal]
array([ 0, 6, 12, 18, 24])
Entonces, ¿qué uso si quiero que vuelva?
array([ 4, 8, 12, 16, 20])
Ahi esta
In [47]: np.diag(np.fliplr(array))
Out[47]: array([ 4, 8, 12, 16, 20])
o
In [48]: np.diag(np.rot90(array))
Out[48]: array([ 4, 8, 12, 16, 20])
De los dos, np.diag(np.fliplr(array))
es más rápido:
In [50]: %timeit np.diag(np.fliplr(array))
100000 loops, best of 3: 4.29 us per loop
In [51]: %timeit np.diag(np.rot90(array))
100000 loops, best of 3: 6.09 us per loop
Aquí hay dos ideas:
step = len(array) - 1
# This will make a copy
array.flat[step:-step:step]
# This will make a veiw
array.ravel()[step:-step:step]
Aquí hay una forma simple de usar el recorte numpy. Personalmente no me resulta muy duro para los ojos (¡pero concedo que fliplr
es un poco más descriptivo!).
Solo para resaltar la contribución de este ejemplo a las respuestas existentes, ejecuté el mismo punto de referencia simple.
In [1]: import numpy as np
In [3]: X = np.random.randint(0, 10, (5, 5))
In [4]: X
Out[4]:
array([[7, 2, 7, 3, 7],
[8, 4, 5, 9, 6],
[0, 2, 9, 0, 4],
[8, 2, 1, 0, 3],
[3, 1, 0, 7, 0]])
In [5]: Y = X[:, ::-1]
In [6]: Z1 = np.diag(Y)
In [7]: Z1
Out[7]: array([7, 9, 9, 2, 3])
Ahora para comparar con la solución más rápida actual dada.
In [8]: step = len(X) - 1
In [9]: Z2 = np.take(X, np.arange(step, X.size-1, step))
In [10]: Z2
Out[10]: array([7, 9, 9, 2, 3])
In [11]: np.array_equal(Z1, Z2)
Out[11]: True
Puntos de referencia
In [12]: %timeit np.diag(X[:, ::-1])
1.92 µs ± 29.5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [13]: %timeit step = len(X) - 1; np.take(X, np.arange(step, X.size-1, step))
2.21 µs ± 246 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
Las comparaciones iniciales indican que mi solución es además de complejidad lineal, mientras que usar la solución del segundo paso no es:
In [14]: big_X = np.random.randint(0, 10, (10000, 10000))
In [15]: %timeit np.diag(big_X[:, ::-1])
2.15 µs ± 96.3 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [16]: %timeit step = len(big_X) - 1; np.take(big_X, np.arange(step, big_X.size-1, step))
100 µs ± 1.85 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Generalmente uso este método para voltear imágenes (reflejarlas) o para convertir entre el formato de opencv
(canales, altura, ancho) al formato de matplotlib
(altura, anchura, canales) . Entonces, para una imagen tridimensional, simplemente se flipped = image[:, :, ::-1]
. Por supuesto, puede generalizarlo para voltear a lo largo de cualquier dimensión, colocando la parte ::-1
en la dimensión deseada.