我有两个大数组A
和b
:
A
:10.000 ++行,4列,不是唯一的整数
b
:具有500.000 ++元素的向量,唯一整数
由于b
值的唯一性,我需要找到b
的唯一索引,其中A(i,j) == b
。
我开始的是
[rows,columns] = size(A);
B = zeros(rows,columns);
for i = 1 : rows
for j = 1 : columns
B(i,j) = find(A(i,j)==b,1);
end
end
这需要大约 5.5秒来计算,这是很长的方式,因为A
和b
可能会显着更大......这就是我试图加速通过使用逻辑索引和减少for循环来增加代码
[rows,columns] = size(A);
B = zeros(rows,columns);
for idx = 1 : numel(b)
B(A==b(idx)) = idx;
end
可悲的是,这需要更长时间: 21秒
我甚至尝试使用bsxfun
for i = 1 : columns
[I,J] = find(bsxfun(@eq,A(:,i),b))
... stitch B together ...
end
但是使用更大的阵列时,最大阵列大小会很快超过(102,9GB ......)。
你能帮我找到更快的解决方案吗?提前谢谢!
编辑:我延长了find(A(i,j)==b
,1
)
,这使得算法加速了2倍!谢谢,但整体还是太慢了......;)
答案 0 :(得分:4)
函数ismember
是正确的工具:
[~,B] = ismember(A,b);
测试代码:
function so
A = rand(1000,4);
b = unique([A(:);rand(2000,1)]);
B1 = op1(A,b);
B2 = op2(A,b);
isequal(B1,B2)
tic;op1(A,b);op1(A,b);op1(A,b);op1(A,b);toc
tic;op2(A,b);op2(A,b);op2(A,b);op2(A,b);toc
end
function B = op1(A,b)
B = zeros(size(A));
for i = 1:numel(A)
B(i) = find(A(i)==b,1);
end
end
function B = op2(A,b)
[~,B] = ismember(A,b);
end
我在Octave上运行了这个,它的循环速度不如MATLAB。它也没有timeit
函数,因此使用tic
/ toc
的时间很糟糕(抱歉)。在Octave中,op2
比op1
快100多倍。时序在MATLAB中会有所不同,但ismember
应该仍然是最快的选择。 (注意我也用单个循环替换了你的双循环,这是相同但更简单,可能更快。)
如果您想在b
中重复进行搜索,首先要对b
进行排序,并实施自己的二分查找。这将避免ismember
所做的检查和排序。请参阅this other question。
答案 1 :(得分:2)
假设你有正整数,你可以使用数组索引:
mm = max(max(A(:)),max(b(:)));
idxs = sparse(b,1,1:numel(b),mm,1);
result = full(idxs(A));
如果值的范围很小,您可以使用密集矩阵而不是稀疏矩阵:
mm = max(max(A(:)),max(b(:)));
idx = zeros(mm,1);
idx(b)=1:numel(b);
result = idx(A);