3

假设我有两个长度不同的向量 A 和 B,Length(A) is not equal to Length(B)并且向量 A 中的值与向量 B 中的值不同。我想将 B 的每个值与 A 的值进行比较(比较意味着如果值 B(i) 是A(1:end)例如的值几乎相同B(i)-Tolerance<A(i)<B(i)+Tolerance

for loop由于数据很大,我怎么能不使用呢?

我知道ismember(F),intersect,repmat,find 但这些功能都不能真正帮助我

4

5 回答 5

3

您可以尝试以下方面的解决方案:

tol = 0.1; 

N = 1000000; 

a = randn(1, N)*1000; % create a randomly

b = a + tol*rand(1, N); % b is "tol" away from a

a_bin = floor(a/tol); 
b_bin = floor(b/tol); 

result = ismember(b_bin, a_bin) | ...
         ismember(b_bin, a_bin-1) | ...
         ismember(b_bin, a_bin+1); 

find(result==0) % should be empty matrix. 

这个想法是将 a 和 b 变量离散化为大小为 的箱tol。然后,您询问是否在与 a 中的任何元素相同的 bin 中找到 b,或者在其左侧的 bin 中,或在其右侧的 bin 中。

优点:我相信ismember里面很聪明,首先对元素进行排序a,然后对每个元素执行次线性 (log(N)) 搜索。这与显式构造 b 中的每个元素与 a 中的元素的差异的方法不同,这意味着复杂性与 a 中的元素数量成线性关系。

比较N=100000在我的机器上运行 0.04 秒,而使用线性搜索的时间为 20 秒(使用 Alan 简洁明了的tf = arrayfun(@(bi) any(abs(a - bi) < tol), b);解决方案计时)。

缺点:这导致实际公差介于 tol 和 1.5*tol 之间。取决于您的任务是否可以忍受(如果唯一关心的是浮点比较,则可以)。

注意:这是否可行取决于 a 和 b 的范围以及 tol 的值。如果 a 和 b 可能非常大而 tol 非常小,则a_binandb_bin将无法解析单个 bin(那么您将不得不使用整数类型,再次仔细检查它们的范围是否足够)。带循环的解决方案更安全,但如果你真的需要速度,你可以投资优化提出的想法。当然,另一种选择是编写一个 mex 扩展。

于 2013-07-12T11:29:47.960 回答
2

听起来您正在尝试做的是具有ismember用于实际有价值数据的功能。

也就是说,检查向量中的每个值是否B(i)在向量中至少一个值的容差阈值内BB(i)TA

这会产生如下结果:

tf = false(1, length(b)); %//the result vector, true if that element of b is in a
t = 0.01; %// the tolerance threshold
for i = 1:length(b)
    %// is the absolute difference between the 
    %//element of a and b less that the threshold?
    matches = abs(a - b(i)) < t; 

    %// if b(i) matches any of the elements of a
    tf(i) = any(matches);
end

或者,简而言之:

t = 0.01;
tf = arrayfun(@(bi) any(abs(a - bi) < t), b);

关于避免 for 循环:虽然这可能受益于矢量化,但如果您的数据如此庞大,您可能还需要考虑查看并行化。在这种情况下,像我的第一个示例中那样使用 for 循环会很方便,因为您可以通过更改forto轻松地进行基本版本的并行处理parfor

于 2013-07-12T10:07:35.083 回答
1

这是一个完全矢量化的解决方案。请注意,我实际上会推荐@Alan 给出的解决方案,因为我的解决方案不太可能适用于大数据集。

[X Y]=meshgrid(A,B)
M=abs(X-Y)<tolerance 

现在可以得到 a 中在容差范围内的元素的逻辑索引,any(M)并且 B 的索引由下式找到any(M,2)

于 2013-07-12T10:24:41.737 回答
1

bsxfun救援

 >> M = abs( bsxfun(@minus, A, B' ) ); %//' difference
 >> M < tolerance 
于 2013-07-12T10:49:32.327 回答
0

做你想做的另一种方法是使用逻辑表达式。
由于 A 和 B 是不同大小的向量,因此您不能简单地减去并查找小于公差的值,但您可以执行以下操作:

Lmat = sparse((abs(repmat(A,[numel(B) 1])-repmat(B',[1 numel(A)])))<tolerance);

并且您将得到一个稀疏逻辑矩阵,其中包含与相等元素一样多的元素(在容差范围内)。然后,您可以通过编写来计算您拥有的这些元素的数量:

Nequal = sum(sum(Lmat));

您还可以通过以下方式获取相应元素的索引:

[r,c] = find(Lmat);

那么以下代码将是正确的(对于所有 j in numel(r)):

B(r(j))==A(c(j))

最后,您应该注意,如果 A 或 B 中存在重复条目,则通过这种方式可以获得多个计数。建议首先使用该unique函数。例如:

A_new = unique(A);
于 2018-01-07T11:09:55.563 回答