【问题标题】:optimization of pairwise L2 distance computations成对 L2 距离计算的优化
【发布时间】:2014-04-29 12:05:01
【问题描述】:

我需要帮助来优化这个循环。 matrix_1 是 (nx 2) 整数矩阵,matrix_2 是 (m x 2)、m & n 非常。

index_j = 1;
for index_k = 1:size(Matrix_1,1)
    for index_l = 1:size(Matrix_2,1)
        M2_Index_Dist(index_j,:) = [index_l, sqrt(bsxfun(@plus,sum(Matrix_1(index_k,:).^2,2),sum(Matrix_2(index_l,:).^2,2)')-2*(Matrix_1(index_k,:)*Matrix_2(index_l,:)'))];
        index_j = index_j + 1;
    end
 end

我需要 M2_Index_Dist 提供一个 ((n*m) x 2) 矩阵,第一列中的索引为 matrix_2,第二列中的距离。

输出示例:

M2_Index_Dist = [ 1, 5.465
                  2, 56.52
                  3, 6.21
                  1, 35.3
                  2, 56.52
                  3, 0
                  1, 43.5
                  2, 9.3
                  3, 236.1
                  1, 8.2
                  2, 56.52
                  3, 5.582]

【问题讨论】:

  • 为什么要将bsxfun 应用于两个标量值?你能举一个你想要达到的结果的小例子吗?
  • @FireSky:一个数值例子应该包括输入和输出

标签: performance matlab optimization for-loop bsxfun


【解决方案1】:

以下是如何将bsxfun 应用于您的公式 (||A-B|| = sqrt(||A||^2 + ||B||^2 - 2*A*B)):

d = real(sqrt(bsxfun(@plus, dot(Matrix_1,Matrix_1,2), ...
    bsxfun(@minus, dot(Matrix_2,Matrix_2,2).', 2 * Matrix_1*Matrix_2.')))).';

如果你改变你对矩阵的解释,你可以避免最终的转置。

注意:real 不应该处理任何复杂的值,但它存在于非常小的差异可能导致微小的负数的情况下。


编辑:没有dot 可能会更快:

d = sqrt(bsxfun(@plus, sum(Matrix_1.*Matrix_1,2), ...
    bsxfun(@minus, sum(Matrix_2.*Matrix_2,2)', 2 * Matrix_1*Matrix_2.'))).';

或者只需拨打bsxfun

d = sqrt(bsxfun(@plus, sum(Matrix_1.*Matrix_1,2), sum(Matrix_2.*Matrix_2,2)') ...
    - 2 * Matrix_1*Matrix_2.').';

注意:最后的操作顺序会为您提供相同的结果,而不是错误~1e-14


编辑2:复制M2_Index_Dist

II = ndgrid(1:size(Matrix_2,1),1:size(Matrix_2,1));
M2_Index_Dist = [II(:) d(:)];

【讨论】:

  • 谢谢,这很有用,但你能把matrix_2的索引同时拉出来吗?
  • @FireSky 那不就是idx = repmat(1:size(Matrix_2,1),1,size(Matrix_1,1));吗?或查看新的编辑。
  • @FireSky 只是一个礼貌的碰撞。我的最后一次编辑提供了您所需要的一切,一切都被矢量化了。谢谢。
【解决方案2】:

如果我理解正确,这就是你想要的:

ind = repmat((1:size(Matrix_2,1)).',size(Matrix_1,1),1); %'// first column: index
d = pdist2(Matrix_2,Matrix_1); %// compute distance between each pair of rows
d = d(:); %// second column: distance
result = [ind d]; %// build result from first column and second column

如您所见,此代码调用pdist2 来计算矩阵的每对行之间的距离。默认情况下,此函数使用欧几里得距离。

如果您没有pdist2(属于统计工具箱的一部分),您可以将上面的第 2 行替换为bsxfun

d = squeeze(sqrt(sum(bsxfun(@minus,Matrix_2,permute(Matrix_1, [3 2 1])).^2,2)));

【讨论】:

  • 如果你 tic toc pdist2 和 sqrt 算法;当 sqrt 算法大约需要 0.00004 秒时,pdist2 大约是 0.00026 秒
  • 我在整个代码中多次使用它,并希望在减少时间的同时保持统一
  • 试试bsxfun 版本。在我的机器上,pdist2bsxfun 比你的循环快
  • 上面评论中提到的 sqrt 是问题中的那个,它里面有 bsxfun 。但是,您拥有的 bsxfun 算法(从挤压开始)tic toc 的时间为 0.00012 秒
  • 对不起,我不关注。在我的电脑上,我的代码比你的快。如果你的循环代码对你来说真的更快(据说最近的 Matlab 版本可以很好地运行循环),我怀疑你可以用 Matlab 改进它
猜你喜欢
  • 2017-06-03
  • 1970-01-01
  • 2020-12-26
  • 1970-01-01
  • 2020-10-21
  • 2010-10-11
  • 2020-09-15
  • 2015-03-11
  • 1970-01-01
相关资源
最近更新 更多