【问题标题】:Find the first N non-zero elements in each row of a matrix在矩阵的每一行中查找前 N 个非零元素
【发布时间】:2013-12-13 18:51:25
【问题描述】:

我在 MATLAB 中有一个零矩阵,我想得到另一个矩阵,每行中的第一个 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]

我希望结果是:

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

我有一个巨大的矩阵,所以我想在没有循环的情况下做,你能帮帮我吗?非常感谢!

【问题讨论】:

  • 是否保证每行至少有 N 个非零元素?
  • 是的,我愿意。我保证有超过 N

标签: matlab matrix


【解决方案1】:

由于 MATLAB 根据column-major order 存储矩阵,所以我先转置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];

转置和预分配输出 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

索引零

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

冒泡非零

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

选择第一行N 并转回

B(1:N,:)'

您可以按行优先顺序进行冒泡,但您需要使用 find 检索行和列下标,并在那里进行一些排序和挑选。它变得更加乏味且可读性降低。

【讨论】:

  • 太棒了!这正是我所需要的!非常感谢!
【解决方案2】:

使用不带循环的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

【讨论】:

  • +1 我知道你会想出一个accumarray 解决方案:-)
【解决方案3】:

通常我不使用 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

既然保证A 的每行有多个N 非零值,那应该可以完成工作。

【讨论】:

    【解决方案4】:

    单线解决方案:

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

    不是非常优雅或高效,但非常有趣!

    【讨论】:

    • 单行加分,不能怪你。正如您所指出的,并不比循环快。 ;)
    【解决方案5】:
    N = 3;
    for ii=1:size(A,1);
        B(ii,:) = A( ii,find(A(ii,:),N) );
    end
    

    【讨论】:

    • 我总是忘记'first' 的用法。为提醒 +1。
    • @chappjc 在这种情况下实际上甚至没有必要,至少'first' 是默认的
    • 实际上我的意思是第二个参数,正如您指出的那样,它是默认的。我从来不用那个。
    【解决方案6】:

    其实你可以像打代码那样做:


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

    那我觉得这个B矩阵就是你想要的了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-09
      • 1970-01-01
      • 2014-04-30
      • 2021-06-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多