MATLAB - 给定索引矩阵置换矩阵的列
MATLAB - Permute columns of a matrix given a matrix of indices
给定一个矩阵 X,我想将每列的 k 个最小元素设置为零。对于向量 x,我执行以下操作:
[~, ind] = sort(x)
x(ind(1:k)) = 0
现在,对于矩阵 X,这不起作用:
[~, IND] = sort(X)
X(IND(1:k)) = 0
只需将第一列的第k个最小元素设置为0,如何正确索引呢?
解决方案代码:一种方法sort
(to get column-wise sorted indices) & then 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) Select 仅每列的前 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
给定一个矩阵 X,我想将每列的 k 个最小元素设置为零。对于向量 x,我执行以下操作:
[~, ind] = sort(x)
x(ind(1:k)) = 0
现在,对于矩阵 X,这不起作用:
[~, IND] = sort(X)
X(IND(1:k)) = 0
只需将第一列的第k个最小元素设置为0,如何正确索引呢?
解决方案代码:一种方法sort
(to get column-wise sorted indices) & then 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) Select 仅每列的前 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