Performance 映射2个向量-帮助向量化

Performance 映射2个向量-帮助向量化,performance,matlab,map,vector,vectorization,Performance,Matlab,Map,Vector,Vectorization,在Matlab中,我有两个不同长度的x坐标向量。例如: xm = [15 20 24 25 26 35 81 84 93]; xn = [14 22 26 51 55 59 70 75 89 96]; 我需要将xm映射到xn,或者换句话说,找到xn中最接近xm的坐标。因此,如果我有与这些坐标相关的值,我可以使用这个地图作为索引并关联这些值 两个向量都已排序,每个向量中都没有重复项 我用for循环编写了一个简单的函数: function xmap = vectors_map(xm,xn) xma

在Matlab中,我有两个不同长度的x坐标向量。例如:

xm = [15 20 24 25 26 35 81 84 93];
xn = [14 22 26 51 55 59 70 75 89 96];
我需要将xm映射到xn,或者换句话说,找到xn中最接近xm的坐标。因此,如果我有与这些坐标相关的值,我可以使用这个地图作为索引并关联这些值

两个向量都已排序,每个向量中都没有重复项

我用for循环编写了一个简单的函数:

function xmap = vectors_map(xm,xn)
xmap = zeros(size(xm));
for k=1:numel(xm)
    [~, ind] = min(abs(xm(k)-xn));
    xmap(k) = ind(1);
end
对于上面的例子是返回

xmap =
    1     2     2     3     3     3     8     9    10
它工作正常,但需要一段时间来处理长向量(超过100000个点)


你知道如何将这段代码矢量化吗?

看起来你的输入向量已经排序了。使用二进制搜索查找最接近的匹配项。这将给您一个O(n ln)运行时间。

您的xm和xn已排序。如果通常是这种情况,那么您可以比单步遍历整个阵列做得更好


对于xn中的每个值,都有一个值范围,其中xm中的值比其他任何值都更接近该值。预先计算这些间隔,然后可以依次遍历两个数组。

如David所说,利用排序会更快,因为您有这么多点,但作为参考,矢量化的一种方法是使用meshgrid:

[X Y] = meshgrid(xn, xm);
diffs = X - y;
mins = min(diffs, [], 2);

请注意,这将在内存中创建两个100000 x 100000阵列,因此它可能仅适用于较小的数据集。

请考虑此矢量化解决方案:

[~, xmap] = min( abs(bsxfun(@minus, xm, xn')) )

哦!!另一种选择:由于您要查找两个排序列表之间的密切对应关系,因此可以使用类似于合并的算法同时遍历这两个列表。这应该是O(最大(长度(xm),长度(xn))-ish

编辑:
请看@yuk的评论,上面的代码并不完全正确

我所知道的解决这个问题的最快实现是(可以编译为.mex文件的C代码;对我来说,它比公认答案中的rescdsk代码快20倍左右)。令人惊讶的是,这样一个常见的操作不是MATLAB内置函数。

我在最新版本的MATLAB中使用了新的~语法来跳过一个未使用的变量。如果你有一个更早的版本,就用tmp替换~吧。为了澄清,你想为每个xm[i]建立索引j,这样xm[i]就最接近xn[j]?伙计,我的名字也是汤姆·史密斯!啊,二进制搜索!我没想到+太好了!这段代码让我在10000个长度向量的情况下速度提高了50倍,在100000个长度向量的情况下速度提高了1500倍。如果xn的最后几个元素映射到xm(end),则会返回错误。我刚把第6-7行改成:如果MCool!耶!我很高兴它对你有用!是的,这是关于计算机科学的有趣的事情之一,当你突然使一些东西快了无数倍…是的,它需要大量的内存,比我的小向量函数慢得多。很好的向量化。谢谢但是,它比我的函数慢了两倍,而且需要更多的内存,但比以前的代码要好。谢谢。我还没有试过,但它看起来是一个很好的解决方案。

match_for_xn = zeros(length(xn), 1);
last_M = 1;
for N = 1:length(xn)
  % search through M until we find a match.
  for M = last_M:length(xm)
    dist_to_curr = abs(xm(M) - xn(N));
    dist_to_next = abs(xm(M+1) - xn(N));

    if dist_to_next > dist_to_curr
      match_for_xn(N) = M;
      last_M = M;
      break
    else
      continue
    end

  end % M
end % N