在Python中计算加权的成对距离矩阵

时间:2013-11-20 06:31:20

标签: python numpy matrix scipy scikit-learn

我正在尝试找到在Python中执行以下成对距离计算的最快方法。我想使用距离来对list_of_objects进行相似性排名。

list_of_objects中的每个项目都有四个测量值a,b,c,d,它们是在非常不同的尺度上进行的,例如:

object_1 = [0.2, 4.5, 198, 0.003]
object_2 = [0.3, 2.0, 999, 0.001]
object_3 = [0.1, 9.2, 321, 0.023]
list_of_objects = [object_1, object_2, object_3]

目的是获得list_of_objects中对象的成对距离矩阵。但是,我希望能够通过每个测量一个权重的权重向量来指定我的距​​离计算中每个测量的“相对重要性”,例如:

weights = [1, 1, 1, 1]

表示所有测量值均等。在这种情况下,无论测量范围如何,我都希望每个测量对物体之间的距离做出相同的贡献。可替换地:

weights = [1, 1, 1, 10]

表示我希望测量d比其他测量值对物体之间的距离贡献10倍。

我当前的算法如下所示:

  1. 计算每次测量的成对距离矩阵
  2. 规范化每个距离矩阵,使最大值为1
  3. 将每个距离矩阵乘以weights
  4. 的适当权重
  5. 求和距离矩阵以生成单个成对矩阵
  6. 使用4中的矩阵提供list_of_objects
  7. 对象对的排序列表

    这很好用,并给我一个对象之间城市街区距离的加权版本。

    我有两个问题:

    1. 在不改变算法的情况下,SciPy,NumPy或SciKit-Learn中执行初始距离矩阵计算的最快实现是什么。

    2. 是否存在现有的多维距离方法,可以为我完成所有这些操作?

    3. 对于Q 2,我看过,但找不到任何内置步骤,以我想要的方式做出“相对重要性”。

      其他建议表示欢迎。很高兴澄清我是否错过了细节。

2 个答案:

答案 0 :(得分:9)

scipy.spatial.distance是您想要查看的模块。它有很多不同的规范,可以很容易地应用。

我建议使用加权的Monkowski Metrik

Weighted Minkowski Metrik

您可以使用此程序包中的pdist方法进行成对距离计算。

E.g。

import numpy as np
from scipy.spatial.distance import pdist, wminkowski, squareform

object_1 = [0.2, 4.5, 198, 0.003]
object_2 = [0.3, 2.0, 999, 0.001]
object_3 = [0.1, 9.2, 321, 0.023]
list_of_objects = [object_1, object_2, object_3]

# make a 4x3 matrix from list of objects
X = np.array(list_of_objects)

#calculate pairwise distances, using weighted Minkowski norm
distances = pdist(X,wminkowski,2, [1,1,1,10])

#make a square matrix from result
distances_as_2d_matrix = squareform(distances)

print distances
print distances_as_2d_matrix

这将打印

[ 801.00390786  123.0899671   678.0382942 ]
[[   0.          801.00390786  123.0899671 ]
 [ 801.00390786    0.          678.0382942 ]
 [ 123.0899671   678.0382942     0.        ]]

答案 1 :(得分:3)

归一化步骤,您将成对距离除以最大值,似乎是非标准的,并且可能很难找到一个现成的函数,它将完全按照您的要求执行。虽然自己动手很容易。一个起点是将list_of_objects转换为数组:

>>> obj_arr = np.array(list_of_objects)
>>> obj_arr.shape
(3L, 4L)

然后,您可以使用广播获得成对距离。这样效率有点低,因为它没有利用指标的符号,并计算每个距离两次:

>>> dists = np.abs(obj_arr - obj_arr[:, None])
>>> dists.shape
(3L, 3L, 4L)

规范化非常容易:

>>> dists /= dists.max(axis=(0, 1))

您的最终称量可以通过多种方式完成,您可能希望以最快的速度进行基准测试:

>>> dists.dot([1, 1, 1, 1])
array([[ 0.        ,  1.93813131,  2.21542674],
       [ 1.93813131,  0.        ,  3.84644195],
       [ 2.21542674,  3.84644195,  0.        ]])
>>> np.einsum('ijk,k->ij', dists, [1, 1, 1, 1])
array([[ 0.        ,  1.93813131,  2.21542674],
       [ 1.93813131,  0.        ,  3.84644195],
       [ 2.21542674,  3.84644195,  0.        ]])