【问题标题】:MATLAB - Permute columns of a matrix given a matrix of indicesMATLAB - 在给定索引矩阵的情况下置换矩阵的列
【发布时间】: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。如何正确索引它?

【问题讨论】:

    标签: matlab matrix indexing


    【解决方案1】:

    解决方案代码:一种方法是使用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) 最后,我们使用这些索引在XX(lin_idx) = 0 中选择性地设置零。

    【讨论】:

    • 如果你有时间,你能解释一下 bsxfun 究竟是做什么的吗?有了这样一个优雅的解决方案,这将大大改善这个答案。
    • @BananaCode 在里面添加了一些解释。
    【解决方案2】:

    使用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
    

    【讨论】:

    • 这个答案看起来很有趣。准确解释它的工作原理将极大地提高它的实用性。
    猜你喜欢
    • 1970-01-01
    • 2018-09-09
    • 2014-06-08
    • 2015-11-08
    • 2018-03-26
    • 1970-01-01
    • 2011-12-24
    • 1970-01-01
    • 2016-05-03
    相关资源
    最近更新 更多