我在Matlab中有以下矩阵:
M = [0 0 1
1 0 0
0 1 0
1 0 0
0 0 1];
Run Code Online (Sandbox Code Playgroud)
每行只有一个1.我如何(没有循环)确定列向量,以便第一个元素是2,如果第二列中有1,第二个元素是3,对于第三列中的一个等.?上面的例子应该变成:
M = [ 3
1
2
1
3];
Run Code Online (Sandbox Code Playgroud)
你可以用简单的矩阵乘法来解决这个问题.
result = M * (1:size(M, 2)).';
3
1
2
1
3
Run Code Online (Sandbox Code Playgroud)
这通过将M x 3矩阵与3 x 1阵列相乘来实现,其中3x1的元素是简单的[1; 2; 3].简而言之,对于每一行M,使用3×1阵列执行逐元素乘法.只有行中的1 M将产生结果中的任何内容.然后将该元素乘法的结果相加.因为每行只有一个"1",所以结果将是1所在的列索引.
例如,对于第一行M.
element_wise_multiplication = [0 0 1] .* [1 2 3]
[0, 0, 3]
sum(element_wise_multiplication)
3
Run Code Online (Sandbox Code Playgroud)
更新
根据@reyryeng和@Luis提供的解决方案,我决定进行比较,看看各种方法的性能如何比较.
为了设置测试矩阵(M),我创建了一个原始问题中指定形式的矩阵,并改变了行数.使用随机选择哪一列具有1 randi([1 nCols], size(M, 1)).使用分析执行时间timeit.
使用M类型double(MATLAB的默认值)运行时,您将获得以下执行时间.
如果M是a 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
Run Code Online (Sandbox Code Playgroud)