Matlab - удаление строк и столбцов из матрицы, содержащих 0

Я работаю над проблемой, связанной с отклонением луча (это не слишком весело :P)

Мне нужно преобразовать глобальную матрицу жесткости в матрицу жесткости конструкции, я делаю это, удаляя все строки и столбцы из исходной матрицы, содержащие 0.

Итак, если у меня есть такая матрица (назовем ее K):

0   0   5   3   0   0
0   0   7   8   0   0
7   1   2   6   2   1
3   8   6   9   5   3
0   0   4   5   0   0
0   0   1   8   0   0 

Сокращенная матрица (назовем ее S) будет просто

2   6
6   9

Вот что я написал до сих пор, чтобы свести глобальную матрицу K к матрице жесткости S

S = K;

for i = 1:length(S(:,1))
    for j = 1:length(S(1,:))
        if  S(i,j) == 0
            S(i,:) = [];
            S(:,j) = [];
            break;
        end
    end
end

Однако я получаю «Индекс превышает размеры матрицы» в строке, содержащей оператор «если», и я не уверен, что правильно думаю о лучшем способе удаления всех строк и столбцов. Ценим любой отзыв!


person zZShort_CircuitZz    schedule 26.09.2014    source источник


Ответы (4)


Легкий:

S = K(all(K,2), all(K,1));
person Luis Mendo    schedule 26.09.2014
comment
СВЯТОЙ СМОК это как волшебство! Я должен взглянуть на все функции..... Большое спасибо! - person zZShort_CircuitZz; 27.09.2014
comment
Ха-ха-ха, я буквально смеюсь над вашим комментарием. Спасибо! Взгляните также на это - person Luis Mendo; 27.09.2014
comment
@zZShort_CircuitZz Я внес исправление. Пожалуйста, смотрите обновленный ответ - person Luis Mendo; 27.09.2014
comment
@zZShort_CircuitZz — all — это функция, которая проверяет все строки для определенного столбца или все столбцы для определенной строки в вашей матрице, чтобы убедиться, что все значения не равны нулю. Если это так для конкретной строки/столбца, то вывод будет true / 1, иначе 0. all(K,2) просматривает все столбцы для каждой строки, а all(K,1) просматривает каждую строку для каждого столбца. Выполняя all(K,2), then all(K,1)`, Луис отфильтровывает те строки, в которых есть хотя бы один ноль, а затем использует этот промежуточный результат для фильтрации столбцов, в которых есть хотя бы один ноль. - person rayryeng; 27.09.2014

Для матрицы nxn в качестве альтернативы вы можете попробовать подход, основанный на умножении матриц -

K=[
    0   0   5   3   2   0
    0   0   7   8   7   0
    7   1   6   6   2   1
    3   8   6   8   5   3
    0   0   4   5   5   0
    5   3   7   8   1   6]  %// Slightly different than the one in question

K1 = double(K~=0)
K2 = K1*K1==size(K,1)
K3 = K(K2)
S = reshape(K3,max(sum(K2,1)),max(sum(K2,2)))

Вывод -

S =
     6     6     2
     6     8     5
     7     8     1
person Divakar    schedule 26.09.2014
comment
Очень красивый подход! Использование K1*K1 очень умно. О +0, как вы думаете, это быстрее, чем double(), или просто легче печатать? :-) - person Luis Mendo; 27.09.2014
comment
@LuisMendo Не уверен, какой из них будет быстрее, но в основном интуиция говорит, что +0 будет, и в любом случае он компактен. Также, я думаю, лучше избегать вызовов функций. - person Divakar; 27.09.2014
comment
@LuisMendo Только что провел несколько тестов, чтобы сравнить double() с +0. double() похоже, что он выигрывает с незначительным улучшением на 4%-8% для 1000x1000 вверх размеров данных, в противном случае я думаю, что можно использовать любой из них. - person Divakar; 27.09.2014
comment
Хорошо знать! Я думаю, что тогда я буду придерживаться double() - person Luis Mendo; 27.09.2014

Проблема в том, что когда вы удаляете какую-либо строку или столбец, вы не должны увеличивать i или j, но цикл MATLAB for автоматически обновляет их. Также ваш алгоритм не может обрабатывать такие случаи, как:

0 1 0
1 1 1
1 1 1

Он удалит только первый столбец из-за условия разрыва, поэтому вам нужно удалить его, но как-то правильно обрабатывать индексы. Другой подход может заключаться в том, чтобы сначала взять произведение строк и столбцов, затем проверить эти произведения и удалить соответствующие строки и столбцы, когда элемент произведения равен нулю. Пример реализации в MATLAB может быть таким:

function [S] = stiff(K)
S = K;
% product of each row, rows(k) == 0 if there is a 0 in row k
rows = prod(S,2);
% product of each column, cols(k) == 0 if there is a 0 in column k
cols = prod(S,1);

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

% firstly eliminate the rows
% row numbers in the new matrix
ii=1;
for i = 1:size(S,1),
    if rows(i) == 0,
        S(ii, :) = []; % delete the row
    else
        ii = ii + 1; % skip the row
    end
end

Здесь мы удаляем строки, содержащие нули, вручную обновляя индекс (обратите внимание ii).

% handle the columns now
ii = 1;
for i = 1:size(S,2),
    if cols(i) == 0,
        S(:, ii) = []; % delete the row
    else
        ii = ii + 1; % skip the row
    end
end
end

Здесь мы применяем ту же операцию к остальным столбцам.

person Mehmet Emre    schedule 26.09.2014

Другой метод, который я могу предложить, заключается в преобразовании матрицы K в логическую матрицу, где все, что не равно нулю, равно 1 и 0 в противном случае. Затем вы должны выполнить сумму столбцов в этой матрице, а затем проверить, не суммируются ли какие-либо столбцы с количеством строк, которые у вас есть. Вы удаляете эти столбцы, затем выполняете сумму строк в промежуточной матрице и проверяете, не суммируются ли какие-либо строки с количеством столбцов, которые у вас есть. Вы удаляете эти строки, чтобы остаться с вашей окончательной матрицей. Как таковой:

Kbool = K ~= 0;
colsToRemove = sum(Kbool,1) ~= size(Kbool,1);
K(colsToRemove,:) = [];
rowsToRemove = sum(Kbool,2) ~= size(Kbool,2);
K(:,rowsToRemove) = []; 
person rayryeng    schedule 26.09.2014