如何在Matlab中不使用find函数获取逻辑矩阵的索引?

3

假设矩阵A是比较函数的输出,即只包含0和1的逻辑矩阵。对于一个大小为3*4的小矩阵,我们可能会得到以下结果:

A =

     1     1     0     0
     0     0     1     0
     0     0     1     1

现在,我正在生成另一个矩阵B,它与A具有相同的大小,但其行填充有A的索引,并且每行中任何剩余值都设置为零。

B =

     1     2     0     0
     3     0     0     0
     3     4     0     0

目前,我正在对A的每一行使用find函数来获取矩阵B。完整代码可以编写为:

A=[1,1,0,0;0,0,1,0;0,0,1,1];
[rows,columns]=size(A);
B=zeros(rows,columns);

for i=1:rows
    currRow=find(A(i,:));
    B(i,1:length(currRow))=currRow;
end

对于大矩阵,"find"函数在Matlab Profiler中显示计算时间较长。是否有任何方法可以更快地生成矩阵B?

注意:矩阵A每行有超过1000列,但非零元素从未超过50个。这里,我将矩阵B视为与A相同大小,但矩阵B在列方向上可以比A小得多。


你可以用索引操作替换find,但如果这样做更快的话,我会感到惊讶。I = 1:columns; currRow = I(A(i,:)); - Cris Luengo
我在思考是否可以完全删除“for”循环以实现更快的操作。这可能吗? - lonstud
你是否考虑将矩阵存储为sparse矩阵?我还会存储矩阵的转置,以便在MATLAB中按列进行搜索。 - beaker
2
在Matlab中,for循环不一定慢。历史上它们确实很慢,但现在并不完全正确。根据Cris和beaker的建议,我不认为向量化版本会更快。 - David
1个回答

1
我建议使用parfor,但这里的开销太大,而且还存在更多问题,因此它不是一个好的解决方案。
rows = 5e5;
cols = 1000;
A = rand(rows, cols) < 0.050;
I = uint16(1:cols);
B = zeros(size(A), 'uint16');
% [r,c] = find(A);
tic
for i=1:rows
%     currRow = find(A(i,:));
    currRow = I(A(i,:));
    B(i,1:length(currRow)) = currRow;
end
toc

@Cris建议用索引操作替换find。这样可以提高大约10%的性能。
显然,除非B需要以您指定的特定形式存在,否则没有更好的优化方法。如果不需要矩阵形式的索引,请使用[r,c] = find(A);

我在思考是否可以完全删除“for”循环以实现更快的操作。这可能吗? - lonstud
不,您需要每一行都被单独处理。类似于 I = repmat(uint16(1:cols), rows, 1); B = I(A); 这样的代码可以输出结果,但是它并不能告诉您每个结果属于哪一行。 - Burak

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