Question

I have a m x n matrix where each row consists of zeros and same values for each row.

an example would be:

M = [-0.6 1.8 -2.3 0 0 0; 0 0 0 3.4 -3.8 -4.3; -0.6 0 0 3.4 0 0]

In this example the first column consists of 0s and -0.6, second 0 and 1.8, third -2.3 and so on.

In such case I would like to reduce m to 1 (get a vector from a given matrix) so in this example a vector would be [-0.6 1.8 -2.3 3.4 -3.8 -4.3]

Does anyone know what is the best way to get a vector from such matrix?

Thank you!

Was it helpful?

Solution

Here's a one-liner that uses the function SUM:

nonZeroColumnValues = sum(M)./sum(M ~= 0);

This will return a 1-by-n vector that contains the repeated non-zero value from each column. It does so by summing each column, then dividing the result by the number of non-zero values in each column. If there are no non-zero values in a column, the result for that column will be NaN.

Here's an example using the sample matrix M in the question:

>> M = [-0.6 1.8 -2.3 0 0 0; 0 0 0 3.4 -3.8 -4.3; -0.6 0 0 3.4 0 0]

M =

   -0.6000    1.8000   -2.3000         0         0         0
         0         0         0    3.4000   -3.8000   -4.3000
   -0.6000         0         0    3.4000         0         0

>> nonZeroColumnValues = sum(M)./sum(M ~= 0)

nonZeroColumnValues =

   -0.6000    1.8000   -2.3000    3.4000   -3.8000   -4.3000

OTHER TIPS

If there's an unknown number of non-zeros and zeros, one way to fix the problem is to first replace the zeros with NaNs, and then use something like max or min to find the data.

%# create an array
M = [-0.6 1.8 -2.3 0 0 0; 0 0 0 3.4 -3.8 -4.3; -0.6 0 0 3.4 0 0];

%# replace zeros with NaN
M(M==0) = NaN;

%# get, for each column, the number
numbers = max(M,[],1)

numbers =

    -0.6000    1.8000   -2.3000    3.4000   -3.8000   -4.3000

EDIT

This is how I understood the question: "I want, for every column, to know the value of the non-zero entries. There is only one non-zero number per column, but it could occur multiple times"

Here is a more Matlab-like (but longer) way to get the solution:

%# create an array
    M = [-0.6 1.8 -2.3 0 0 0; 0 0 0 3.4 -3.8 -4.3; -0.6 0 0 3.4 0 0];

%# find the non-zero entries
[r,c] = find(M);

%# only take one entry per column
[uniqueCols, sortIdx] = unique(c);

%# fix the rows correspondingly
uniqueRows = r(sortIdx);

%# convert to index
idx = sub2ind(size(M),uniqueRows,uniqueCols);

%# get the numbers per column (transpose as needed)
numbers = M(idx)

numbers =

   -0.6000
    1.8000
   -2.3000
    3.4000
   -3.8000
   -4.3000

This is NOT actually a sparse matrix. A sparse matrix in MATLAB is defined as such. If you use the sparse or spdiags functions to define that matrix, then the zero elements will not need to be stored, only the non-zeros. Of course, MATLAB knows how to work with these true sparse matrices in conjunction with other standard double arrays.

Finally, true sparse matrices are usually much more sparse than this, or you would not bother to use the sparse storage form at all.

Regardless, if you only want the non-zero elements of ANY matrix, then you can do this:

NZ = M(M ~= 0);

alternatively,

NZ = M(find(M));

Either will string out the non-zeros by columns, because that is how numbers are stored in a matrix in MATLAB.

NZ = M(find(M))
NZ =
         -0.6
         -0.6
          1.8
         -2.3
          3.4
          3.4
         -3.8
         -4.3

In your question, you asked for how to do this by rows, extracting the non-zero elements in the first row, then the second row, etc.

This is most simply done by transposing the array first. Thus, we might do something like...

NZ = M.';
NZ = NZ(find(NZ))
NZ =
         -0.6
          1.8
         -2.3
          3.4
         -3.8
         -4.3
         -0.6
          3.4

See that I used .' to do the transpose, just in case any elements were complex.

M = M(M~=0)

or

M(find(M))

and please learn how to format code for SO readers.

EDIT @Jonas suggests that OP wants only one occurrence of each non-zero element from M. To get this try wrapping either of the foregoing suggestions in unique(), such as

unique(M(M~=0))

If the OP REALLY wants to find the non-zero elements that are also unique, then there are far better ways to do so than Jonas suggests.

The logical solution is to find the non-zero elements FIRST. Then apply the function unique. So do this:

unique(M(find(M)))

If your goal is to find those elements in a specific order, then that order needs to be explicitly defined in your goal.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top