【问题标题】:Finding the column index for the 1 in each row of a matrix查找矩阵每一行中 1 的列索引
【发布时间】:2016-03-11 22:15:17
【问题描述】:

我在 Matlab 中有以下矩阵:

M = [0 0 1
     1 0 0
     0 1 0
     1 0 0
     0 0 1];

每一行只有一个 1。我如何(不循环)确定一个列向量,以便如果第二列中有 1,第一个元素是 2,第二个元素是 3 中的一个第三列等?上面的例子应该变成:

M = [ 3
      1
      2
      1
      3];

【问题讨论】:

    标签: matlab matrix


    【解决方案1】:

    您实际上可以通过简单的矩阵乘法来解决这个问题。

    result = M * (1:size(M, 2)).';
    
         3
         1
         2
         1
         3
    

    这是通过将 M x 3 矩阵与 3 x 1 数组相乘来实现的,其中 3x1 的元素就是 [1; 2; 3]。简而言之,对于M 的每一行,使用 3 x 1 数组执行逐元素乘法。只有M 行中的 1 会在结果中产生任何内容。然后对这个逐元素乘法的结果求和。因为每行只有一个“1”,所以结果将是该 1 所在的列索引。

    例如M的第一行。

    element_wise_multiplication = [0 0 1] .* [1 2 3]
    
        [0, 0, 3]
    
    sum(element_wise_multiplication)
    
        3
    

    更新

    基于下面@reyryeng@Luis提供的解决方案,我决定进行比较,看看各种方法的性能比较。

    为了设置测试矩阵 (M),我创建了原始问题中指定形式的矩阵并改变了行数。使用randi([1 nCols], size(M, 1)) 随机选择哪一列有 1。使用timeit分析执行时间。

    当使用 double 类型的 M(MATLAB 的默认设置)运行时,您将获得以下执行时间。

    如果Mlogical,则矩阵乘法会受到影响,因为它必须在矩阵乘法之前转换为数值类型,而其他两个有一点性能改进.

    这是我使用的测试代码。

    sizes = round(linspace(100, 100000, 100));
    times = zeros(numel(sizes), 3);
    
    for k = 1:numel(sizes)
        M = generateM(sizes(k));
        times(k,1) = timeit(@()M * (1:size(M, 2)).');
        M = generateM(sizes(k));
        times(k,2) = timeit(@()max(M, [], 2), 2);
        M = generateM(sizes(k));
        times(k,3) = timeit(@()find(M.'), 2);
    end
    
    figure
    plot(range, times / 1000);
    legend({'Multiplication', 'Max', 'Find'})
    xlabel('Number of rows in M')
    ylabel('Execution Time (ms)')
    
    function M = generateM(nRows)
        M = zeros(nRows, 3);
        col = randi([1 size(M, 2)], 1, size(M, 1));
        M(sub2ind(size(M), 1:numel(col), col)) = 1;
    end
    

    【讨论】:

    • 非常感谢您的快速答复。这是完美的。
    【解决方案2】:

    你也可以滥用find,观察M转置的位置。您必须先转置矩阵,因为find 按列主要顺序运行:

    M = [0 0 1
         1 0 0
         0 1 0
         1 0 0
         0 0 1];
    
    [out,~] = find(M.');
    

    不确定这是否比矩阵乘法更快。

    【讨论】:

    • find[out,~] = ...out = ... 不同的罕见情况之一
    • @LuisMendo 啊哈是的先生!
    【解决方案3】:

    另一种方法:使用max的第二个输出:

    [~, result] = max(M.', [], 1);
    

    或者,按照@rayryeng 的建议,沿第二个维度使用max,而不是转置M

    [~, result] = max(M, [], 2);
    

    对于

    M = [0 0 1
         1 0 0
         0 1 0
         1 0 0
         0 0 1];
    

    这给了

    result =
         3     1     2     1     3
    

    如果M 在给定行中包含多个1,这将给出第一个这样的1 的索引。

    【讨论】:

    • 做得很好。我总是忘记以这种方式使用max。我想知道所有方法之间的性能比较是什么。我的钱在max
    • 如果您没有转置矩阵并指定沿矩阵的行查看,是否存在性能差异?就像将要查看的维度指定为 2?
    猜你喜欢
    • 2013-04-20
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-13
    • 1970-01-01
    • 2016-07-09
    • 1970-01-01
    相关资源
    最近更新 更多