Как отсортировать двухмерный массив в коде по количеству нулей в строке?

Есть массив, некоторые элементы которого равны нулю. Нужно отсортировать его по количеству нулей в строках, кроме последнего столбца. Где строка с наибольшим количеством нулей будет последней, а с наименьшим или без - первой.

Вообще, это решение нужно для перестановки строк матрицы в привычный вид для решения СЛАУ.

Код:

import copy
import numpy as np


def maxArr(arr):
    max = abs(arr[0][0])
    for i in range(len(arr)):
        for j in range(len(arr)):
            if max < abs(arr[i][j]):
                max = abs(arr[i][j])
                row = i
                col = j
    return max, row, col


def printArr(arr):
    for i in range(len(arr)):
        for j in range(len(arr[i])):
            print("%2.4f" % (arr[i][j]), end = ' ')
        print(" ")
    print(" ")


arrM = np.array([[3.81, 0.25, 1.28, 1.75, 4.21],
        [2.25, 1.32, 5.58, 0.49, 7.47],
        [5.31, 7.28, 0.98, 1.04, 2.38],
        [10.39, 2.45, 3.35, 2.28, 11.48]]);

arrR = copy.copy(arrM)

arrY = np.array([[0.0] * len(arrM[0])] * len(arrM))

x = [0] * len(arrM)
r = [0] * len(arrM)

for k in range(len(arrM)):
    print("Матрица M[" + str(k) + "]: ")
    printArr(arrM)
    max, p, q = maxArr(arrM)
    m = [0] * len(arrM)

    for i in range(len(arrM)):
        if i != p:
            # подсчет коеф. м
            m[i] = -(arrM[i][q]/arrM[p][q]) 
            for j in range(len(arrM[i])):
                # умножаем элементы неглавных строк на коеф. м
                arrM[i][j] += arrM[p][j]*m[i]

    #"вычеркиваем" элементы главной строчки
    for i in range(len(arrM[0])):
        arrY[p][i] = arrM[p][i]
        arrM[p][i] = 0

print("Результат прямого хода: ")
printArr(arrY)

Конкретно в моем коде нужно преобразить массив arrY из такого

0.0000 -0.0000 0.0000 0.9005 -0.3449  
0.0000 -0.0000 4.9504 0.0127 5.4406  
0.0000 6.0279 -0.7321 -0.1252 -3.4871  
10.3900 2.4500 3.3500 2.2800 11.4800  

в такой

10.3900 2.4500 3.3500 2.2800 11.4800  
0.0000 6.0279 -0.7321 -0.1252 -3.4871  
0.0000 -0.0000 4.9504 0.0127 5.4406  
0.0000 -0.0000 0.0000 0.9005 -0.3449  

Мне подсказали такое решение, но оно не работает с моим кодом.

printArr(arrY[(arrY==0).sum(axis=1).argsort()])

Ответы (1 шт):

Автор решения: MaxU

По-моему "проблема" в том, что в вашей матрице встречаются значения, которые стремятся к нулю, но при строгом сравнении с нулем выдают False, о чем вы забыли упомянуть в вопросе:

In [11]: arrY
Out[11]:
array([[ 0.00000000e+00, -6.09777900e-19,  0.00000000e+00,  9.00524911e-01, -3.44918767e-01],
       [ 0.00000000e+00, -1.11022302e-16,  4.95041956e+00,  1.26575251e-02,  5.44063920e+00],
       [ 0.00000000e+00,  6.02788258e+00, -7.32078922e-01, -1.25235804e-01, -3.48706449e+00],
       [ 1.03900000e+01,  2.45000000e+00,  3.35000000e+00,  2.28000000e+00,  1.14800000e+01]])

поэтому можно воспользоваться np.isclose(...):

In [14]: printArr(arrY[np.isclose(arrY, 0, atol=1e-07).sum(axis=1).argsort()])
10.3900 2.4500 3.3500 2.2800 11.4800
0.0000 6.0279 -0.7321 -0.1252 -3.4871
0.0000 -0.0000 4.9504 0.0127 5.4406
0.0000 -0.0000 0.0000 0.9005 -0.3449

UPD: в решении выше с нулем сравниваются все столбцы, включая последний. Если последний столбец сравнивать не нужно, то это делается так:

res = arrY[np.isclose(arrY[:, :-1], 0, atol=1e-07).sum(axis=1).argsort()]
→ Ссылка