在 space 中查找靠近另一个数组的数组元素?

Finding array elements close to another array in space?

我基本上想使用函数 ismember,但用于一个范围。例如,对于 array2.

中的每个元素,我想知道 array1 中的哪些数据点在 array2n 距离内

我有以下内容:

array1 = [1,2,3,4,5]
array2 = [2,2,3,10,20,40,50]

我想知道 array2 中的哪些值与 array1 相差 <= 2:

indices(1,:) (where array1(1) = 1)     = [1 1 1 0 0 0 0]
indices(2,:) (where array1(2) = 2)     = [1 1 1 0 0 0 0]
indices(3,:) (where array1(3) = 3)     = [1 1 1 0 0 0 0]
indices(4,:) (where array1(4) = 4)     = [1 1 1 0 0 0 0]
indices(5,:) (where array1(5) = 5)     = [0 0 1 0 0 0 0]

缺点:

我的array1是496736个元素,我的array2是9268个元素,所以我宁愿不用循环

使用MATLAB R2016b中引入的implicit expansion,你可以简单地写:

abs(array1.' - array2) <= 2

ans =
  1  1  1  0  0  0  0
  1  1  1  0  0  0  0
  1  1  1  0  0  0  0
  1  1  1  0  0  0  0
  0  0  1  0  0  0  0

对于较早的 MATLAB 版本,您可以使用 bsxfun 函数获取此信息:

abs(bsxfun(@minus, array1.', array2)) <= 2

ans =
  1  1  1  0  0  0  0
  1  1  1  0  0  0  0
  1  1  1  0  0  0  0
  1  1  1  0  0  0  0
  0  0  1  0  0  0  0

希望对您有所帮助!

P.S。关于"MATLAB is slow for loops"神话,请看at that blog post为例。


编辑:请阅读关于使用此and/or他的方法的 RAM 消耗!

循环是此处的有效选项。将数组 output 初始化为 array1 X array2 的大小,然后遍历 array1 中的所有元素并从中减去 array2,然后检查绝对值是否小于或等于到 2:

array1 = [1,2,3,4,5];
array2 = [2,2,3,10,20,40,50];

output = zeros(numel(array1), numel(array2),'logical');

for ii = 1:numel(array1)
   output(ii,:) = abs(array1(ii)-array2)<=2;
end
output =

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

即循环不是问题。

感谢Rahnema1的建议,可以直接将output初始化为逻辑矩阵:

output = zeros(numel(array1),numel(array2),'logical');

其大小仅为 4.3GB。


关于计时:Hans 的代码在几秒钟内运行 array1 = 5*rand(496736,1); array2 = 25*rand(9286,1);,循环解决方案需要大约 15 倍的时间。两种解决方案彼此相等。 obcahrdon 的 ismembertol 解决方案在我的机器上介于两者之间。


关于 RAM 使用情况:

  • 根据 Hans 的回答,隐式扩展以及我建议的循环都只需要 4.3GB 内存就可以扩展问题大小 (496736*9286)
  • 另一方面,
  • bsxfun 根据 Hans' 尝试创建一个 34GB 的中间双矩阵(它甚至不适合我的 RAM,所以我无法比较时间) .
  • 解决方案输出不同形式的解决方案,占用 ~5.04GB(高度依赖于找到的匹配项数量,越多,这个数字就越大)。

总的来说,这让我得出结论,隐式扩展应该是您的选择,但如果您有 R2016a 或更早版本,ismembertol 或循环是可行的方法。

如果您有 Statistics Toolbox,您可以使用 pdist2 来计算距离矩阵:

result = pdist2(array1(:), array2(:)) <= 2;

@Adriaan, this is not efficient for large input sizes. In that case a better approach is a loop with preallocation of the logical matrix output, as in 所述。

您还可以将 ismembertol 与某些特定选项一起使用:

A       = [1,2,3,4,5];
B       = [2,2,3,10,20,40,5000];
tol     = 2;
[~,ind] = ismembertol([A-tol;A+tol].',[B-tol;B+tol].',tol, 'ByRows', true, ...
    'OutputAllIndices', true, 'DataScale', [1,Inf])

它将创建一个 5x1 元胞数组,其中包含对应的 linear indice

ind{1} = [1,2,3]
ind{2} = [1,2,3]
...
ind{5} = [3]

在这种情况下使用线性索引而不是逻辑索引将大大减少内存消耗。