The problem is in:
for i in range(5):
linha_aux = linha_aux + 1
if pivos_indices[i] > pivos_indices[linha_aux] and linha_aux < 5 and i < 5:
You have an array of 5 elements, the maximum value that reaches i
in your for
is 4, but for i
= 4 linha_aux
is 5 and pivos_indices[5]
is not valid because that index is out of range for an array of 5 elements (where the maximum index is 4) . and linha_aux < 5
does not serve as protection because it is not evaluated, since indexing occurs before it is evaluated.
The logical thing to do is to make the for
iterate up to len(array) - 1
, in this case for i in range(4)
.
There is a simpler way to sort the array according to the number of initial consecutive zeros. Using your idea of using np.nonzero
we can use the resulting array with the pivot index. Then we order it and get the indexes of the ordered elements ( numpy.argsort
) and finally we indexed mat
with it:
import numpy as np
def buscar_pivo(L):
p = np.nonzero(L)[1]
if p.size:
return p[0]
return L.size
mat = np.matrix([[0, 5, 2, 7, 8],
[0, 0, 0, 14, 16],
[0, 0, 0, 0, 0],
[0, 0, 10, 16, 22],
[0, 0, 0, 0, 8]]).astype(float)
res = mat[np.argsort(np.apply_along_axis(buscar_pivo, axis=1, arr=mat))]
print(res)
Exit:
[[ 0. 5. 2. 7. 8.]
[ 0. 0. 10. 16. 22.]
[ 0. 0. 0. 14. 16.]
[ 0. 0. 0. 0. 8.]
[ 0. 0. 0. 0. 0.]]
For your original example we get:
>>> mat = np.matrix([[0, 5, 2, 7, 8],
[8, 10, 4, 14, 16],
[0, 0, 0, 0, 0],
[2, 6, 10, 16, 22],
[3, 5, 8, 9, 15]]).astype(float)
>>> res = mat[np.argsort(np.apply_along_axis(buscar_pivo, axis=1, arr=mat))]
>>> res
[[ 8. 10. 4. 14. 16.]
[ 2. 6. 10. 16. 22.]
[ 3. 5. 8. 9. 15.]
[ 0. 5. 2. 7. 8.]
[ 0. 0. 0. 0. 0.]]
Edit:
-
The function buscar_pivo
has been modified to adapt to our needs. Previously -1 was returned if the row is null (all elements are 0). The problem is that when ordering the indexes of the pivots these rows would be the first, when they should be the last. For this reason, instead of returning -1 the size of the row is returned. For a 5 x 5 matrix, return 5, since the maximum index is 4, these lines will always be ordered at the end.
-
np.apply_along_axis(buscar_pivo, axis=1, arr=mat)
iterates over the rows of the matrix mat
creating an array with the outputs resulting from applying the function buscar_pivo
to each row. That is, call buscar_pivo
for each row, passing that row as an argument to the function and create a new array with the results. The argument axis
indicates on which axis of the matrix we are going to apply the function. In a 2d matrix the 0 axis is the x axis (columns) and the 1 axis is the y axis (rows). In this case we use the axis 1 since what we want to pass to buscar_pivo
are the rows. If we have a 3d array we can iterate on the z axis with axis = 3
, and so on. Let's see it with an example:
>>> import numpy as np
>>> array = np.array[[1, 2],
[5, 9],
[-4, 3]]
# Funcción estúpida que retorna la suma de los elementos de un array:
>>> def suma(arr):
return np.sum(arr)
# Suma de los elementos de cada columna:
>>> s = np.apply_along_axis(suma, axis=0, arr=array)
>>> s
array([ 2, 14])
# Suma de los elementods de cada fila:
>>> s = np.apply_along_axis(suma, axis=1, arr=array)
>>> s
array([ 3, 14, -1])
-
np.argsort
instead of returning the ordered array returns the indexes of those ordered elements.
>>> import numpy as np
>>> array = np.array([4, 2, 1, 5])
>>> s = array.argsort()
>>> s
array([2, 1, 0, 3]) #Se corresponden con los indices de 1, 2, 4 y 5
-
Finally we can index an array by passing it an index array:
>>> import numpy as np
>>> array = np.array([4, 2, 1, 5])
>>> s = array[[3, 0, 1, 2]]
>>> s
array([5, 4, 2, 1])