【发布时间】:2015-05-30 09:28:35
【问题描述】:
给定一个矩阵 X,我想将每列的 k 个最小元素设置为零。对于向量 x,我执行以下操作:
[~, ind] = sort(x)
x(ind(1:k)) = 0
现在,对于矩阵 X,这不起作用:
[~, IND] = sort(X)
X(IND(1:k)) = 0
只需将第一列的 k 最小元素设置为 0。如何正确索引它?
【问题讨论】:
给定一个矩阵 X,我想将每列的 k 个最小元素设置为零。对于向量 x,我执行以下操作:
[~, ind] = sort(x)
x(ind(1:k)) = 0
现在,对于矩阵 X,这不起作用:
[~, IND] = sort(X)
X(IND(1:k)) = 0
只需将第一列的 k 最小元素设置为 0。如何正确索引它?
【问题讨论】:
解决方案代码:一种方法是使用sort(获取按列排序的索引)然后bsxfun(获取线性排序索引)-
%// Get 2D array of column-sorted indices for input X
[~,sorted_idx] = sort(X,1)
%// Get linear indices for the first k rows of sorted indices
lin_idx = bsxfun(@plus,sorted_idx(1:k,:),[0:size(X,2)-1]*size(X,1))
%// Use those indices to set them in X as zeros
X(lin_idx) = 0;
示例运行
1) 输入:
X =
61 67 86 54 49 40 13
48 91 28 70 34 98 87
79 7 27 86 71 58 52
16 10 45 60 79 4 3
56 36 49 50 31 48 87
k =
3
2) 排序索引:
>> [~,sorted_idx] = sort(X,1)
sorted_idx =
2 3 2 1 1 1 1
4 4 3 4 2 4 3
5 5 4 5 5 5 4
1 1 5 2 3 3 2
3 2 1 3 4 2 5
3) 只选择每列的前 k 个索引:
>> sorted_idx(1:k,:)
ans =
4 3 3 5 5 4 4
2 4 2 1 2 1 1
5 5 4 4 1 5 3
4) 我们需要将这些列索引转换为对应于二维数组X 的线性索引。因此,在 MATLAB 中使用的列主要索引之后,第一列保持原样,第二列必须添加 number of rows in X 的偏移量,第三列将添加 2*number of rows in X,依此类推,直到所有列都覆盖。
从数学上讲,我们将[0 5 10 15 20 25 30],即[0:6]*5,即作为通用案例[0:size(X,2)-1]*size(X,1),添加到sorted_idx(1:k,:)。由于我们需要对sorted_idx(1:k,:) 的每一行都执行此操作,因此我们可以对bsxfun 使用自动扩展和求和(使用@plus)。请注意,这将以矢量化方式完成。因此,这里[0:size(X,2)-1]*size(X,1) 的扩展将沿行发生,然后将使用@plus 执行与sorted_idx(1:k,:) 的元素求和。因此,我们将拥有像这样急需的线性索引 -
>> lin_idx = bsxfun(@plus,sorted_idx(1:k,:),[0:size(X,2)-1]*size(X,1))
lin_idx =
4 8 13 20 25 29 34
2 9 12 16 22 26 31
5 10 14 19 21 30 33
5) 最后,我们使用这些索引在X 和X(lin_idx) = 0 中选择性地设置零。
【讨论】:
使用quantile(统计工具箱):
X = X .* bsxfun(@ge, X, quantile(X, k/size(X,1)));
工作原理:
quantile(X, k/size(X,1)) 为每一列提供一个数字(分位数),使得该列中条目的一部分 k/size(X,1)) 小于该数字。这意味着,在每一列中,k 条目正好小于列分位数。bsxfun(@ge, ...)) 进行比较,得到一个矩阵,其中包含小于分位数的条目的 0,否则包含 1。A 乘以 2 的结果使 A 的所需值等于 0。示例:
>> X = rand(5,3)
X =
0.088188645571510 0.907109055220371 0.805984932289666
0.683710335821638 0.860456667336885 0.868488116302772
0.120400876857723 0.338451384118250 0.669646599875533
0.010699003144174 0.027158829325862 0.807778862315076
0.557268230074914 0.800859355130033 0.897498282302820
>> k=2;
>> X = X.*bsxfun(@ge, X, quantile(X,k/size(X,1)))
X =
0 0.907109055220371 0
0.683710335821638 0.860456667336885 0.868488116302772
0.120400876857723 0 0
0 0 0.807778862315076
0.557268230074914 0.800859355130033 0.897498282302820
【讨论】: