7
votes

I would like to remove some columns and rows from a big matrix. Those are the columns and the rows which have all zeros values. Is there any function in MATLAB that can do it for you quite fast? My matrices are sparse. I am doing this way:

 % To remove all zero columns from A
 ind = find(sum(A,1)==0) ;
 A(:,ind) = [] ;

 % To remove all zeros rows from A
 ind = find(sum(A,2)==0) ;
 A(ind,:) = [] ;

It would be nice to have a line of code for this as I may do this kind of task repeatedly. Thanks

2
Your code looks good. If your matrices are sparse it may be faster though when you copy the non-zero elements (don't know, just a guess): B = A(~ind,:). - Matthias W.
using all(A,1) or all(A,2) might be faster than sum(A,1), but I didn't check. - Max
Thanks. You are right, I was checking any and all. The best option seems to be this: A(:,~any(A)) = [] (to remove zero columns) and A(~any(A'),:) = [] (to remove all zero rows). Please confirm - Yas
@Yas I would think A(~any(A,2),:) = [] would be faster than A(~any(A'),:) = []. You might also want to try A = A(any(A,2),:) rather as the =[] can be slower: stackoverflow.com/questions/12421345/… - Dan
@GameOfThrows: I don't see this question being a duplicate. The other question addresses removing all zeros. - Daniel

2 Answers

9
votes

A single line of code would be:

A=A(any(X,2),any(X,1))

There is no need to use find like you did, you can directly index using logical vectors.

2
votes

1 Dimension:

I'll first show a simpler example based on another duplicate question, asking to to remove only the rows containing zeros elements.

Given the matrix A=[1,2;0,0];

To remove the rows of 0, you can:

  • sum the absolute value of each rows (to avoid having a zero sum from a mix of negative and positive numbers), which gives you a column vector of the row sums.

  • keep the index of each line where the sum is non-zero.

in code:

A=[1,2;0,0];
% sum each row of the matrix, then find rows with non-zero sum
idx_nonzerolines = sum(abs(A),2)>0 ;
% Create matrix B containing only the non-zero lines of A
B = A(idx_nonzerolines,:) ;

will output:

>> idx_nonzerolines = sum(abs(A),2)>0
idx_nonzerolines =
     1
     0
>> B = A(idx_nonzerolines,:)
B =
     1     2

2 Dimensions:

The same method can be used for 2 dimensions:

A=[ 1,2,0,4;
    0,0,0,0;
    1,3,0,5];

idx2keep_columns = sum(abs(A),1)>0 ;
idx2keep_rows    = sum(abs(A),2)>0 ;

B = A(idx2keep_rows,idx2keep_columns) ;

outputs:

>> B = A(idx2keep_rows,idx2keep_columns)
B =
     1     2     4
     1     3     5

Thanks to @Adriaan in comments for spotting the edge case ;)