保持每列n个最大值,并在没有循环的MATLAB中将其余值设置为零

时间:2015-07-28 18:12:42

标签: arrays matlab sorting indexing vectorization

我有一个未排序的数字矩阵,我希望每列保留n个最大(不一定是唯一的)值,并将其余值设置为零。

我想出了如何用循环来做到这一点:

a = [4 8 12 5; 9 2 6 18; 11 3 9 7; 8 9 12 4]
k = 2

for  n = 1:4
    [y, ind] = sort(a(:,n), 'descend');
    a(ind(k+1:end),n) = 0;
end
a

给了我: a =

 4     8    12     5
 9     2     6    18
11     3     9     7
 8     9    12     4

k =

 2

a =

 0     8    12     0
 9     0     0    18
11     0     0     7
 0     9    12     0

然而,当我尝试消除循环时,我似乎无法正确编制索引,因为这样:

a = [4 8 12 5; 9 2 6 18; 11 3 9 7; 8 9 12 4]
k = 2

[y, ind] = sort(a, 'descend');
b = ind(k+1:end,:)
a(b) = 0

这给了我:(这不是我想做的) a =

 4     8    12     5
 9     2     6    18
11     3     9     7
 8     9    12     4

k =

 2

b =

 4     3     3     1
 1     2     2     4

a =

 0     8    12     5
 0     2     6    18
 0     3     9     7
 0     9    12     4

我索引这个错误吗?我必须使用循环吗?

我引用了这个问题来开始,但这并不是我想要做的事情:How to find n largest elements in an array and make the other elements zero in matlab?

2 个答案:

答案 0 :(得分:2)

你非常接近。 ind函数中的sort为您提供了每个列的行位置,其中该特定值将出现在已排序的输出中。如果要正确索引矩阵并消除条目,则需要执行一些额外的工作。您知道,对于I的每一列,它告诉您我们需要从该特定列中删除这些条目。因此,我要做的是使用I的每一列生成列主线性索引作为我们需要消除的行。

尝试这样做:

a = [4 8 12 5; 9 2 6 18; 11 3 9 7; 8 9 12 4];
k = 2;
[y, ind] = sort(a, 'descend');

%// Change here
b = sub2ind(size(a), ind(k+1:end,:), repmat(1:size(a,2), size(a,1)-k, 1));
a(b) = 0;

我们使用sub2ind来帮助我们生成列主索引,其中行由ind元素之后的k中的值表示,我们需要的列是每列在这个矩阵中。在排序后截断size(a,1)-k值后,剩余k行,因此我们生成的列值从1到a中的列数和尽可能多的列剩下的行。

我们得到了这个输出:

>> a

a =

     0     8    12     0
     9     0     0    18
    11     0     0     7
     0     9    12     0

答案 1 :(得分:2)

这是使用bsxfun -

的人
%// Get descending sorting indices per column
[~, ind] = sort(a,1, 'descend')

%// Get linear indices that are to be set to zeros and set those in a to 0s
rem_ind = bsxfun(@plus,ind(n+1:end,:),[0:size(a,2)-1]*size(a,1))
a(rem_ind) = 0

示例运行 -

a =
     4     8    12     5
     9     2     6    18
    11     3     9     7
     8     9    12     4
n =
     2
ind =
     3     4     1     2
     2     1     4     3
     4     3     3     1
     1     2     2     4
rem_ind =
     4     7    11    13
     1     6    10    16
a =
     0     8    12     0
     9     0     0    18
    11     0     0     7
     0     9    12     0