简体   繁体   English

在矩阵的每一行中找到前N个非零元素

[英]Find the first N non-zero elements in each row of a matrix

I have a matrix in MATLAB with zeroes and I would like to get another matrix with the first N non-zero elements in each row. 我在MATLAB中有一个零的矩阵,我想在每行中得到前N个非零元素的另一个矩阵。 Let's say for example N = 3 , and the matrix is 假设例如N = 3 ,而矩阵为

A = [ 0 0 2 0 6 7 9;
      3 2 4 7 0 0 6;
      0 1 0 3 4 8 6;
      1 2 0 0 0 1 3]

I'd like the result to be: 我希望结果是:

B = [2 6 7;
     3 2 4;
     1 3 4;
     1 2 1]

I have a huge matrix so I would like to do it without a loop, could you please help me? 我有一个巨大的矩阵,所以我想不加循环地进行操作,您能帮我吗? Thanks a lot! 非常感谢!

Since MATLAB stores a matrix according to column-major order , I first transpose A , bubble up the non-zeros, and pick the first N lines, and transpose back: 由于MATLAB根据列的主要顺序存储矩阵,因此我首先转置A ,使非零冒泡,然后选择前N条线,然后转置回去:

N = 3;
A = [ 0 0 2 0 6 7 9;
      3 2 4 7 0 0 6;
      0 1 0 3 4 8 6;
      1 2 0 0 0 1 3];

Transpose and preallocate output B 转置并预分配输出B

At = A';
B = zeros(size(At));

At =
     0     3     0     1
     0     2     1     2
     2     4     0     0
     0     7     3     0
     6     0     4     0
     7     0     8     1
     9     6     6     3

Index zeros 索引零

idx = At == 0;

idx =
     1     0     1     0
     1     0     0     0
     0     0     1     1
     1     0     0     1
     0     1     0     1
     0     1     0     0
     0     0     0     0

Bubble up the non-zeros 冒泡非零

B(~sort(idx)) = At(~idx);

B =
     2     3     1     1
     6     2     3     2
     7     4     4     1
     9     7     8     3
     0     6     6     0
     0     0     0     0
     0     0     0     0

Select first N rows and transpose back 选择前N行并转置回去

B(1:N,:)'

You can do the bubbling in row-major order, but you would need to retrieve the row and column subscripts with find, and do some sorting and picking there. 您可以按行优先的顺序进行冒泡,但是您需要使用find检索行和列下标,并在那里进行一些排序和选择。 It becomes more tedious and less readable. 它变得更加乏味且可读性较差。

Using accumarray with no loops: 使用没有循环的accumarray

N = 3;
[ii,jj] = find(A); [ii,inds]=sort(ii); jj = jj(inds);
lininds = ii+size(A,1)*(jj-1);
C = accumarray(ii,lininds,[],@(x) {A(x(1:N)')}); %' cell array output
B = vertcat(C{:})
B =
     2     6     7
     3     2     4
     1     3     4
     1     2     1

Usually I don't go with a for loop solution, but this is fairly intuitive: 通常我不使用for循环解决方案,但这很直观:

N = 3;
[ii,jj] = find(A);
B = zeros(size(A,1),N);
for iRow = 1:size(A,1),
    nzcols = jj(ii==iRow);
    B(iRow,:) = A(iRow,nzcols(1:N));
end

Since you are guaranteed to have more than N nonzeros per row of A , that should get the job done. 由于可以保证A每行有N非零,所以应该可以完成工作。

N = 3;
for ii=1:size(A,1);
    B(ii,:) = A( ii,find(A(ii,:),N) );
end

One-liner solution: 一线解决方案:

B = cell2mat(cellfun(@(c) c(1:N), arrayfun(@(k) nonzeros(A(k,:)), 1:size(A,1), 'uni', false), 'uni', false)).'

Not terribly elegant or efficient, but so much fun! 不是非常优雅或高效,而是非常有趣!

Actually , you can do it like the code blow: 实际上,您可以像代码打击一样做到这一点:


N=3
 for n=1:size(A,1)
   [a b]=find(A(n,:)>0,N);
   B(n,:)=A(n,transpose(b));
end

Then I think this B matrix will be what you want. 然后我认为这个B矩阵将是您想要的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM