【问题标题】:Matlab: Euclidean norm (or difference) between two vectorsMatlab:两个向量之间的欧几里得范数(或差)
【发布时间】:2019-04-21 16:36:01
【问题描述】:

我想计算向量 G 和数组 C 的每一行之间的欧几里得距离,同时将每一行除以向量 GSD 中的一个值。我所做的似乎非常效率低下。我最大的开销是什么? 我可以加快速度吗?

m=1E7;
G=1E5*rand(1,8);
C=1E5*[zeros(m,1),rand(m,8)]; 
GSD=10*rand(1,8);

%I've taken the log10 of the values because G and C are very large in magnitude. 
%Don't know if it's worth it.

for i=1:m
    dG(i,1)=norm((log10(G)-log10(C(i,2:end)))/log10(GSD));
end

使用下面的示例,它们并没有给出相同的答案。事实上,他们都没有给出相同的答案(见下图使用:

dG = pdist2(log10(G),log10(C(:,2:end)),'mahalanobis',diag(log10(GSD))); %(1)

dG = sqrt(sum((log10(G)-log10(C(:,2:end))./log10(GSD)).^2,2)); 

tmp=bsxfun(@rdivide,bsxfun(@minus,log10(G),log10(C(:,2:end))),log10(GSD)); %(4)
dG = sqrt(sum(tmp.^2,2));

【问题讨论】:

  • 这三个中哪一个给出的答案与您自己的代码相同?我猜想 Mahalanobis 是错误的,但我没有立即看出其他两个有什么不同。
  • 另外,您在取数据的对数时确实会更改数学。我不明白你为什么这样做,为什么你认为你在计算欧几里得距离。我不会在你的代码中使用log10
  • @CrisLuengo G 是一些实验数据,GSD 是 G 中每个点的标准偏差。C 是通过尝试不同的参数值从数学模型预测 G。我想找到一个参数值,使 C 中的一行最小化 C 和 G 之间的差异,这考虑了标准偏差的影响。所以我想我应该记录日志,以防数量级存在差异。你怎么看?
  • 好吧,请注意log(std(x))~=std(log(x)),所以我认为您的标准化不再正确。如果你想计算数据的对数的欧几里得距离,那很好,但是先取对数,然后归一化,或者先归一化,然后取对数。你什么都不做。通常,归一化(白化)应该处理数量级的差异。另请注意log(G)-log(C) = log(G./C),想想这对您的数据意味着什么!

标签: matlab


【解决方案1】:

您可以使用pdist2(x,y) 计算xy 中所有元素之间的成对距离,因此您的示例类似于

dG = pdist2(log10(G),log10(C(:,2:end)),'mahalanobis',diag(log10(GSD)).^2);

其中名称对'mahalanobis',diag(log10(GSD)).^2log10(GSD) 作为欧几里德上的权重,这就是众所周知的马氏距离。

请注意,马氏距离最初是为了规范化数据,因此它是“协方差”,必须作为第四个输入,然后 MATLAB 找到对角线时 (element-wise squareroot) 的 Cholesky 分解,如这里)。

隐式扩展

在较新的 MATLAB 版本中,也可以只是隐式扩展,因为第一个条目只有 1 个向量。

dG = sqrt(sum(((log10(G)-log10(C(:,2:9)))./log10(GSD)).^2,2));

这可能会快一点,但是我确实更喜欢pdist2 解决方案,因为我发现它更清晰。

【讨论】:

  • 谢谢 Nicky,这里我的向量比数组的行少 1 个元素。创建一个新的虚拟变量 Cdum=C(:,2:9); 会更快吗?
  • 不,没关系。无论如何,您都必须对其进行索引。
  • 对不起,我误会了。你是什​​么意思'无论如何你都必须索引它'?
  • 这不是问题,C(:,2:9) 应该可以工作,变量C 在你的例子中是10 long 所以C(:,2:9)~=C(:,2:end)。问题是我误解了GSD 的使用。给我一点时间来解决它。
  • 我弄错了,size(C)=[m,9]。
【解决方案2】:

浮点应该处理大量的输入数据,直到float数据的某个点和double数据的任何合理值

realmax('single')
ans =
  3.4028e+38

realmax('double')
ans =
  1.7977e+308

对于 +/- 1e5 范围内的 1e7 值,您可能期望欧几里得距离的平方在 +/- 1e17 范围内 (5+5+7),这两种格式都可以轻松处理。

在任何情况下,您都应该对代码进行矢量化以移除循环(Matlab 有处理效率非常低的历史,尤其是在旧版本中)

对于新版本(2016b 及更高版本),只需使用:

tmp=(log10(G)-log10(C(:,2:end)))./log10(GSD);
dG = sqrt(sum(tmp.^2,2)); %row-by-row norm

请注意,您必须使用./,这是一个元素除法,而不是/,它是矩阵右除法。

以下代码在任何地方都可以使用

tmp=bsxfun(@rdivide,bsxfun(@minus,log10(G),log10(C(:,2:end))),log10(GSD));
dG = sqrt(sum(tmp.^2,2)); %row-by-row norm

然而,我认为使用 log10 是一个数学错误。结果 dG 将不是是欧几里得范数。你应该坚持加权差的均方根:

dG = sqrt(sum(bsxfun(@rdivide,bsxfun(@minus,G,C(:,2:end)),GSD).^2,2)); % all versions
dG = sqrt(sum((G-C(:,2:end)./GSD).^2,2)); %R2016b and later

【讨论】:

  • 非常感谢 Brice 的回答。为什么说log10是数学错误?我不一定要使用欧几里得距离,但它确实需要考虑 GSD 的值。 GSD实际上是G中每个点的标准差。C的每一行都是G的预测。
  • 我又在看这些了。他们没有给出相同的距离(见上图)。有什么想法吗?
猜你喜欢
  • 2014-03-27
  • 2014-05-31
  • 2014-11-12
  • 2014-06-08
  • 1970-01-01
  • 2016-04-09
  • 2019-06-19
  • 2016-09-11
相关资源
最近更新 更多