如何通过为scipy.cdist重塑numpy数组或使用sklearn来有效地构建距离矩阵?

问题描述

我正在尝试构建具有不同长度数组的距离矩阵。距离度量是hausdorff距离,适用于此类操作。但是,我找不到使用scipy.cdist函数构建距离矩阵的方法

在这里寻找scipy cdist docs在这里寻找hausdorff distance pip install traj-dist在这里similar question

现在,我可以使用scipytraj_dist获取两个数组之间的距离。

import numpy as np
from scipy.spatial import distance
import traj_dist.distance as tdist
from scipy.spatial.distance import directed_hausdorff
from sklearn.metrics import pairwise_distances
# np.float64 needed for tdist import
arr1 = np.array([10,22,1,32,88],dtype=np.float64).reshape(3,2)
arr2 = np.array([1,88,55,11,99,1233],dtype=np.float64).reshape(4,2)
# measuring just for 1 array at the time works fine
tdist.hausdorff(array_of_arrays[0],array_of_arrays[1])
directed_hausdorff(array_of_arrays[0],array_of_arrays[1])

我可以使用嵌套的for循环来计算距离矩阵,但是当n_observation大时,这非常慢。

n_observations = array_of_arrays.shape[0]
distance_matrix = np.zeros((n_observations,n_observations))

for i in range(n_observations):
    for j in range(i + 1,n_observations):
        dist = tdist.hausdorff(np.float64(array_of_arrays[i]),np.float64(array_of_arrays[j]),type_d='spherical')
        distance_matrix[i,j] = dist
        distance_matrix[j,i] = dist

但是我无法使用scipy.cdist使其更大规模地工作。

array_of_arrays = np.array([arr1,arr2])

distance.cdist(array_of_arrays,array_of_arrays,lambda x,y: tdist.hausdorff(x,y))
distance.cdist(array_of_arrays,y: directed_hausdorff(x,y))

sklearn.metrics.pairwise_distance也不起作用


pairwise_distances(array_of_arrays,metric=tdist.hausdorff)

问题是:如何重塑array_of_arrays以在其上使用scipy.cdist

奖励子问题:如果scipy.cdist不适合此类任务,该如何避免嵌套的for循环并计算distance_matrix?

解决方法

从我看到的问题是,有向Hausdorff距离是在两个尺寸为(N,D)和(M,D)的数组之间计算的,并且没有为一维数组(即矢量)定义。 cdist仅将2D数组作为输入,这意味着这些张量的每一行都被视为单独的观察值。要使用SciPy的cdist解决此问题,您将需要能够将3D张量传递给cdist,而这是设计不允许的(它检查张量的维数)。

一种可能的解决方法(这不容易)是获取用Cython(https://github.com/scipy/scipy/blob/v1.5.2/scipy/spatial/_hausdorff.pyx)编写的定向Hausdorff距离的源代码,并尝试对其进行矢量化。