Python 矩阵与向量之间的欧氏距离

Python 矩阵与向量之间的欧氏距离,python,numpy,Python,Numpy,从另一个向量的每列计算一个向量的欧几里德数。 这是正确的吗 distances=np.sqrt(np.sum(np.square(new_v-val.reshape(10,1)),axis=0)) new_v是一个矩阵。 val.reformate(10,1)是一个列向量。 另一种/更好的方法。你可以利用高效的- 或者,使用(a-b)^2=a^2+b^2-2ab公式- out = np.sqrt(np.einsum('ij,ij->j',new_v, new_v) + val.dot(v

从另一个向量的每列计算一个向量的欧几里德数。 这是正确的吗

distances=np.sqrt(np.sum(np.square(new_v-val.reshape(10,1)),axis=0))
new_v是一个矩阵。 val.reformate(10,1)是一个列向量。
另一种/更好的方法。

你可以利用高效的-

或者,使用
(a-b)^2=a^2+b^2-2ab
公式-

out = np.sqrt(np.einsum('ij,ij->j',new_v, new_v) + val.dot(val) - 2*val.dot(new_v))
如果
new_v
的第二个轴很大,我们也可以
numexpr
模块来计算最后的
sqrt
部分

运行时测试

接近-

import numexpr as ne

def einsum_based(new_v, val):
    subs = new_v - val[:,None]
    return np.sqrt(np.einsum('ij,ij->j',subs,subs))

def dot_based(new_v, val):
    return np.sqrt(np.einsum('ij,ij->j',new_v, new_v) + \
                            val.dot(val) - 2*val.dot(new_v))

def einsum_numexpr_based(new_v, val):
    subs = new_v - val[:,None]
    sq_dists = np.einsum('ij,ij->j',subs,subs)
    return ne.evaluate('sqrt(sq_dists)')

def dot_numexpr_based(new_v, val):
    sq_dists = np.einsum('ij,ij->j',new_v, new_v) + val.dot(val) - 2*val.dot(new_v)
    return ne.evaluate('sqrt(sq_dists)')
时间安排-

In [85]: # Inputs
    ...: new_v = np.random.randint(0,9,(10,100000))
    ...: val = np.random.randint(0,9,(10))


In [86]: %timeit np.sqrt(np.sum(np.square(new_v-val.reshape(10,1)),axis=0))
    ...: %timeit einsum_based(new_v, val)
    ...: %timeit dot_based(new_v, val)
    ...: %timeit einsum_numexpr_based(new_v, val)
    ...: %timeit dot_numexpr_based(new_v, val)
    ...: 
100 loops, best of 3: 2.91 ms per loop
100 loops, best of 3: 2.1 ms per loop
100 loops, best of 3: 2.12 ms per loop
100 loops, best of 3: 2.26 ms per loop
100 loops, best of 3: 2.43 ms per loop

In [87]: from numpy.linalg import norm

# @wim's solution
In [88]: %timeit norm(new_v.T-val, axis=1, ord=2)
100 loops, best of 3: 5.88 ms per loop

你所说的是对的。在
numpy.linalg
中有一个更简单的方法:

from numpy.linalg import norm
norm(new_v.T-val, axis=1, ord=2)

new\u v
的形状是什么?大概是任意n的
(10,n)
。一个典型的
n
值会激发我们进行一些计时:)发布的解决方案对你有用吗?依我看,这比OP的原始代码更慢、更长、更不清晰。@wim添加了计时,如果你对性能感兴趣的话。关于“清晰”,好吧,如果我对
norm
一无所知,我想我可以对其他解决方案说同样的话。我使用了
new\u v=np.random.rand(10,1000)
val=np.random.rand(10)
。事实上,第一种方法是使用两行,速度更快。我最初尝试的是单线性方法。整数输入的计时很奇怪。你应该用浮点数表示距离,而不是整数。从性能的角度来说,你认为你把2D数组换成浮点数是错误的。如果您添加一个带有
val
的新轴,然后沿
axis=0
使用norm,您将看到改进:
norm(new_v-val[:,None],axis=0,ord=2)
。我运行了几次,这似乎无关紧要,可能是因为它使用了转置,而转置只是一个视图,没有在那里进行复制。所以,我想你很好。是的,我注意到将一维向量重塑为二维列向量稍微快一点,而不是转置矩阵。但是OP从未说过最大性能是目标,所以我更喜欢可读性最好的方法。
from numpy.linalg import norm
norm(new_v.T-val, axis=1, ord=2)