【问题标题】:python: fastest way to compute euclidean distance of a vector to every row of a matrix?python:计算向量到矩阵每一行的欧几里得距离的最快方法?
【发布时间】:2020-08-21 06:06:52
【问题描述】:

考虑这个 python 代码,我尝试计算向量到矩阵每一行的欧几里距离。与我使用 Tullio.jl 找到的最佳 Julia 版本相比,它非常慢。

python 版本需要 30s,而 Julia 版本只需要 75ms

我确信我在 Python 方面做得不是最好的。有更快的解决方案吗?欢迎使用 Numba 和 numpy 解决方案。

import numpy as np

# generate
a = np.random.rand(4000000, 128)

b = np.random.rand(128)

print(a.shape)
print(b.shape)



def lin_norm_ever(a, b):
    return np.apply_along_axis(lambda x: np.linalg.norm(x - b), 1, a)


import time
t = time.time()
res = lin_norm_ever(a, b)
print(res.shape)
elapsed = time.time() - t
print(elapsed)

朱莉娅版本

using Tullio
function comp_tullio(a, c)
    dist = zeros(Float32, size(a, 2))
    @tullio dist[i] = (c[j] - a[j,i])^2

    dist
end
@time comp_tullio(a, c)

@benchmark comp_tullio(a, c) # 75ms on my computer

【问题讨论】:

  • 此外,如果您使用链接问答答案中的方法#5,请在距离上使用np.sqrt。使用方法 #2,cdist(matrix, np.atleast_2d(search_vec)).ravel().
  • 您查看过链接的问答吗?方法#5 和方法#2 回答问题。如果没有,我错过了什么?如果你能证明那些不适合你,我很乐意重新开放。
  • 在我的(非常新的 8 核)计算机上 comp_tullio 需要 >400 毫秒。你运行了多少线程?
  • 我得到了 6 个线程,一年多前我从 Jsut 得到了一个 i7
  • 我在 Windows 10 上使用 Julia 1.5。

标签: python numpy numba


【解决方案1】:

为了获得最佳性能,我将在此示例中使用 Numba。我还添加了来自 Divakars 链接答案的 2 种方法进行比较。

代码

import numpy as np
import numba as nb
from scipy.spatial.distance import cdist

@nb.njit(fastmath=True,parallel=True,cache=True)
def dist_1(mat,vec):
    res=np.empty(mat.shape[0],dtype=mat.dtype)
    for i in nb.prange(mat.shape[0]):
        acc=0
        for j in range(mat.shape[1]):
            acc+=(mat[i,j]-vec[j])**2
        res[i]=np.sqrt(acc)
    return res

#from https://stackoverflow.com/a/52364284/4045774
def dist_2(mat,vec):
    return cdist(mat, np.atleast_2d(vec)).ravel()

#from https://stackoverflow.com/a/52364284/4045774
def dist_3(mat,vec):
    M = mat.dot(vec)
    d = np.einsum('ij,ij->i',mat,mat) + np.inner(vec,vec) -2*M
    return np.sqrt(d)

时间安排

#Float64
a = np.random.rand(4000000, 128)
b = np.random.rand(128)
%timeit dist_1(a,b)
#122 ms ± 3.86 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit dist_2(a,b)
#484 ms ± 3.02 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit dist_3(a,b)
#432 ms ± 14.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

#Float32
a = np.random.rand(4000000, 128).astype(np.float32)
b = np.random.rand(128).astype(np.float32)
%timeit dist_1(a,b)
#68.6 ms ± 414 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit dist_2(a,b)
#2.2 s ± 32.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
#looks like there is a costly type-casting to float64
%timeit dist_3(a,b)
#228 ms ± 8.13 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-09-23
    • 1970-01-01
    • 2014-08-15
    • 1970-01-01
    • 1970-01-01
    • 2020-06-16
    • 2016-08-02
    • 2012-06-27
    相关资源
    最近更新 更多