我在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];
result = M * (1:size(M, 2)).';
3
1
2
1
3
[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的默认值)时,您将获得以下执行时间。
如果M
是一个logical
,那么矩阵乘法会受到影响,因为它必须在矩阵乘法之前转换为数字类型,而其他两个则有一些性能改进。
这是我使用的测试代码。
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
您还可以滥用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 = ...
不同。 - Luis Mendomax
的方法。我想知道所有方法之间的性能比较如何。我认为max
会更好。 - rayryeng