在一个矩阵的每一行中找到数字1所在的列索引

5

我在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];
3个回答

5
你可以通过简单的矩阵乘法来解决这个问题。
result = M * (1:size(M, 2)).';

     3
     1
     2
     1
     3

这是通过将您的M x 3矩阵与一个3 x 1的数组相乘来实现的,其中3x1的元素只是[1; 2; 3]。简而言之,对于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分析执行时间。

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

enter image description here

如果M是一个logical,那么矩阵乘法会受到影响,因为它必须在矩阵乘法之前转换为数字类型,而其他两个则有一些性能改进。

enter image description here

这是我使用的测试代码。

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

非常感谢您的快速回复。非常完美。 - machinery

2

您还可以滥用find并观察M的转置的位置。您必须先转置矩阵,因为find按列主序操作:

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

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

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


1
find 是少数几个情况之一,其中 [out,~] = ...out = ... 不同。 - Luis Mendo
@LuisMendo 是的先生! - rayryeng

2
另一种方法:使用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会更好。 - rayryeng
2
如果您没有转置矩阵并指定沿着矩阵的行查看,是否会有性能差异?比如指定要查看的维度为“2”? - rayryeng

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接