自定义距离的距离矩阵

4
据我所知,scipy函数scipy.spatial.distance_matrix返回提供的向量矩阵中任意一对向量的闵可夫斯基距离。是否有一种方法可以获得不同距离的相同结果?类似于distance_matrix(X, Y, distance_function)
我假设scipy在幕后进行了某种优化。由于我处理的向量非常大,我不想通过实现自己的distance_matrix函数失去这些优化的好处。

文档显示它返回“所有成对距离的矩阵”,你在哪里读到它返回闵可夫斯基距离的? - Cristofor
请查看此页面,它可能会有所帮助 https://docs.scipy.org/doc/scipy/reference/spatial.distance.html - Cristofor
从文档中得知:"p : float, 1 <= p <= infinity,用于指定使用的Minkowski p-范数。" - usernumber
1
当然,嗯,我不确定是否有这样一个函数“distance_matrix(X, Y, distance_function)”,但你可以做的是根据scipy中已经存在的距离重写你的自定义距离函数。 - Cristofor
1
你可能不需要 distance_matrix(它看起来像是一个辅助函数),而是需要 pdist/cdist(支持自定义度量标准),可能还要跟上 squareform。是的,需要阅读一些文档才能理解这些方法中各种输入和输出的假设。distance_matrix 是针对明可夫斯基距离硬编码的。 - sascha
根据我对pdist文档的理解,我只能从距离列表中选择一个距离。 “距离函数可以是'braycurtis'、 'canberra'、 'chebyshev'、 'cityblock'、 'correlation'、 'cosine'、 'dice'、 'euclidean'、 'hamming'、 'jaccard'、 'jensenshannon'、 'kulsinski'、 'mahalanobis'、 'matching'、 'minkowski'、 'rogerstanimoto'、 'russellrao'、 'seuclidean'、 'sokalmichener'、 'sokalsneath'、 'sqeuclidean'、 'yule'。” - usernumber
1个回答

0

这很容易自己实现

而且性能很可能比scipy中已经实现的距离函数更好。

大多数距离函数都是在所有对上应用一个函数并将其加起来,例如(A_ik-B_jk)**n用于闵可夫斯基距离,最后应用一些其他函数,例如acc**(1/n)

模板函数

您无需更改此处任何内容即可实现各种距离函数。

import numpy as np
import numba as nb

def gen_cust_dist_func(kernel_inner,kernel_outer,parallel=True):

    kernel_inner_nb=nb.njit(kernel_inner,fastmath=True,inline='always')
    kernel_outer_nb=nb.njit(kernel_outer,fastmath=True,inline='always')

    def cust_dot_T(A,B):
        assert B.shape[1]==A.shape[1]

        out=np.empty((A.shape[0],B.shape[0]),dtype=A.dtype)
        for i in nb.prange(A.shape[0]):
            for j in range(B.shape[0]):
                acc=0
                for k in range(A.shape[1]):
                    acc+=kernel_inner_nb(A[i,k],B[j,k])
                out[i,j]=kernel_outer_nb(acc)
        return out

    if parallel==True:
        return nb.njit(cust_dot_T,fastmath=True,parallel=True)
    else:
        return nb.njit(cust_dot_T,fastmath=True,parallel=False)

示例和时间

#Implement for example a Minkowski distance and euclidian distance
#Minkowski distance p=20
inner=lambda A,B:(A-B)**20
outer=lambda acc:acc**(1./20)
my_minkowski_dist=gen_cust_dist_func(inner,outer,parallel=True)

#Euclidian distance
inner=lambda A,B:(A-B)**2
outer=lambda acc:np.sqrt(acc)
my_euclidian_dist=gen_cust_dist_func(inner,outer,parallel=True)

from scipy.spatial.distance import cdist

A=np.random.rand(1000,50)
B=np.random.rand(1000,50)

#Minkowski p=20
%timeit res_1=cdist(A,B,'m',p=20)
#1.44 s ± 8.18 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit res_2=my_minkowski_dist(A,B)
#10.8 ms ± 105 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
res_1=cdist(A,B,'m',p=20)
res_2=my_minkowski_dist(A,B)
print(np.allclose(res_1,res_2))
#True

#Euclidian
%timeit res_1=cdist(A,B,'euclidean')
#39.3 ms ± 307 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%timeit res_2=my_euclidian_dist(A,B)
#3.61 ms ± 22.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
res_1=res_1=cdist(A,B,'euclidean')
res_2=my_euclidian_dist(A,B)
print(np.allclose(res_1,res_2))
#True

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接