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) 的扩展将沿行进行,然后使用 @plussorted_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) 最后,我们使用这些索引在 XX(lin_idx) = 0 中选择性地设置零。

使用quantile(统计工具箱):

X = X .* bsxfun(@ge, X, quantile(X, k/size(X,1)));

工作原理:

  1. quantile(X, k/size(X,1)) 为每一列给出一个数字(分位数),使得该列中条目的分数 k/size(X,1)) 小于该数字。这意味着,在每一列中,恰好 k 个条目小于列分位数。
  2. 将每一列与相应的分位数 (bsxfun(@ge, ...)) 进行比较,得到一个矩阵,其中包含小于分位数的条目 0,否则为 1
  3. 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