python distance函数_关于python:仅使用NumPy计算马氏距离

我正在寻找计算两个numpy数组(x和y)之间的马氏距离的NumPy方法。

以下代码可以使用Scipy的cdist函数正确计算出相同的值。 由于此函数在我的情况下会计算出不必要的后缀,因此我想仅使用NumPy进行更直接的计算。

import numpy as np

from scipy.spatial.distance import cdist

x = np.array([[[1,2,3,4,5],

[5,6,7,8,5],

[5,6,7,8,5]],

[[11,22,23,24,5],

[25,26,27,28,5],

[5,6,7,8,5]]])

i,j,k = x.shape

xx = x.reshape(i,j*k).T

y = np.array([[[31,32,33,34,5],

[35,36,37,38,5],

[5,6,7,8,5]],

[[41,42,43,44,5],

[45,46,47,48,5],

[5,6,7,8,5]]])

yy = y.reshape(i,j*k).T

results =  cdist(xx,yy,'mahalanobis')

results = np.diag(results)

print results

[ 2.28765854  2.75165028  2.75165028  2.75165028  0.          2.75165028

2.75165028  2.75165028  2.75165028  0.          0.          0.          0.

0.          0.        ]

我的审判:

VI = np.linalg.inv(np.cov(xx,yy))

print np.sqrt(np.dot(np.dot((xx-yy),VI),(xx-yy).T))

有人可以纠正这种方法吗?

这是它的公式:

http://docs.scipy.org/doc/scipy-0.14.0/reference/generation/scipy.spatial.distance.mahalanobis.html#scipy.spatial.distance.mahalanobis

我想计算[1,11]和[31,41]之间的马氏距离; [2,22]和[32,42]等。

scipy中的实现是纯python代码。您可以将自己的方法与他们的方法进行比较。有关两个向量之间的马哈拉诺比斯距离的计算,请参见此处:github.com/scipy/scipy/blob/有关观察矩阵的距离的计算,您可能必须遍历每个观察向量。

是的,我尝试从该来源进行计算,但是由于我对Python的了解很少,因此尚未完成。你能看看我的审判吗?

您的方法仅与辣味(包括已转置的delta)不同,而辣味的源代码不会在第二次出现时转置delta ...

@jkalden认为这是一个错误,我已在此处提交了报告mail.scipy.org/pipermail/scipy-dev/2014-December/020301.html

@jkalden我的仅基于numpy的试用版无法正常工作,您能解决吗?

在scipy源中,u和v是一维数组,因此进行转置(用ndarray表示)没有区别。

@xnx oho很高兴知道,谢谢。

您能否再说一遍您要在这里做什么:即为什么您输入的是二维数组?您是否要通过向量对广播马氏距离计算?

是的,我想计算[1,11]和[31,41]之间的马氏距离; [2,22]和[32,42]等。

我认为您的问题出在协方差矩阵的构建上。 尝试:

X = np.vstack([xx,yy])

V = np.cov(X.T)

VI = np.linalg.inv(V)

print np.diag(np.sqrt(np.dot(np.dot((xx-yy),VI),(xx-yy).T)))

输出:

[ 2.28765854  2.75165028  2.75165028  2.75165028  0.          2.75165028

2.75165028  2.75165028  2.75165028  0.          0.          0.          0.

0.          0.        ]

要在没有隐式创建中间数组的情况下执行此操作,您可能必须为Python一个循环牺牲一个C循环:

A = np.dot((xx-yy),VI)

B = (xx-yy).T

n = A.shape[0]

D = np.empty(n)

for i in range(n):

D[i] = np.sqrt(np.sum(A[i] * B[:,i]))

编辑:实际上,使用np.einsum伏都教,您可以删除Python循环并加快很多速度(在我的系统上,从84.3μs到2.9μs):

D = np.sqrt(np.einsum('ij,ji->i', A, B))

编辑:正如@Warren Weckesser指出的那样,einsum也可以用于消除中间的A和B数组:

delta = xx - yy

D = np.sqrt(np.einsum('nj,jk,nk->n', delta, VI, delta))

感谢您的尝试,已投票。实际上,我希望避免使用np.diag来减少不必要的计算以加快速度。

非常感谢。我可以知道C循环是什么意思吗?

NumPy例程"在幕后"使用已编译的C代码,因此它们比字节码已编译的Python循环要快得多(但您必须预先定义数据类型和数组大小)。这就是为什么我最近的编辑中的einsum解决方案比D的Python循环快得多的原因。

请为我解释np.einsum(ij,ji-> i,A,B)做什么?主要是ij,ji-> i的含义。我希望你不介意。

einsum实现爱因斯坦求和约定。 NumPy文档具有更多详细信息,但此调用基本上通过将A的行乘以B的列来实现矩阵(点)乘积,但仅输出(->)位于结果对角线上的那些元素。

np.cov(X.T)产生协方差矩阵而不是协方差,它真的需要协方差矩阵而不是协方差吗?如果不是,计算协方差是否仅会加速进一步的过程?

您可以将einsum用于完整的产品:delta = xx - yy; D = np.sqrt(np.einsum(nj,jk,nk->n, delta, VI, delta))

@WarrenWeckesser太棒了!您介意解释一下您的代码吗?

将其分为两个步骤:p1 = einsum(nj,jk->nk, delta, VI)与delta.dot(VI)相同。 p2 = einsum(nk,nk->n, p1, delta)是p1和delta行的成对点积。查看其他示例的einsum文档字符串。

与einsum一样快的另一个简单解决方案

e = xx-yy

X = np.vstack([xx,yy])

V = np.cov(X.T)

p = np.linalg.inv(V)

D = np.sqrt(np.sum(np.dot(e,p) * e, axis = 1))

你可能感兴趣的:(python,distance函数)