如何有效地计算多个时间序列的欧氏距离矩阵

How to efficiently calculate euclidean distance matrix for several timeseries

我有 6 个时间序列数据如下,即 t1、t2、t3、t4、t5 和 t6。

import numpy as np
series = np.array([
     [0., 0, 1, 2, 1, 0, 1, 0, 0],
     [0., 1, 2, 0, 0, 0, 0, 0, 0],
     [1., 2, 0, 0, 0, 0, 0, 1, 1],
     [0., 0, 1, 2, 1, 0, 1, 0, 0],
     [0., 1, 2, 0, 0, 0, 0, 0, 0],
     [1., 2, 0, 0, 0, 0, 0, 1, 1]])

我想从这 6 个时间序列创建一个欧氏距离矩阵,格式为(即 6*6,其中 x 表示相应的欧氏距离):

     t1  t2  t3  t4  t5  t6
t1    0   x   x   x   x   x
t2    x   0   x   x   x   x
t3    x   x   0   x   x   x
t4    x   x   x   0   x   x
t5    x   x   x   x   0   x
t6    x   x   x   x   x   0

我目前正在手动构造这个矩阵,如下所示(在这个SO问题中:这种方法获得了最高的性能)。

例如,计算 t3 和 t6 之间的欧氏距离。

def eudis(v1, v2):
    dist = [(a - b)**2 for a, b in zip(v1, v2)]
    dist = math.sqrt(sum(dist))
    return dist

eudis(t3, t6)

不过,我确信在 python 中可以有更简单且计算效率更高的方法来执行此操作。如果您有任何建议,请告诉我。

如果需要,我很乐意提供更多详细信息。

您根本不需要循环,因为两个数组之间的欧几里德距离只需​​计算差值的元素平方:

def euclidean_distance(v1, v2):
    return np.sqrt(np.sum((v1 - v2)**2)) 

对于距离矩阵,你有 sklearn.metrics.pairwise.euclidean_distances:

from sklearn.metrics.pairwise import euclidean_distances

euclidean_distances(a).round(2)

array([[0.  , 2.83, 3.74, 0.  , 2.83, 3.74],
       [2.83, 0.  , 2.83, 2.83, 0.  , 2.83],
       [3.74, 2.83, 0.  , 3.74, 2.83, 0.  ],
       [0.  , 2.83, 3.74, 0.  , 2.83, 3.74],
       [2.83, 0.  , 2.83, 2.83, 0.  , 2.83],
       [3.74, 2.83, 0.  , 3.74, 2.83, 0.  ]])

np.allclose(
    eudis(series[2], series[3]),
    euclidean_distance(series[2], series[3])
)
# True

也可以用pdist得到距离矩阵:

from scipy.spatial.distance import pdist, squareform
squareform(pdist(series))


and 解决方案的性能比较:

因此对于相对较小的数据集(最多约 20 个系列,每个系列 200 个元素)pdist 最快,对于较大的数据集 euclidean_disances 表现更好。 pure numpy 大部分速度较慢,并且可能无法为大型数据集分配中间数组。
使用 np.random.randint(0, 100, (n, 10*n)).astype('int16')、numpy 1.17.4、scipy 1.4.1、sklearn 0.23.1、python 3.8.2、Win10 64 位进行测试。

您可以在一行中用简单的 numpy 创建一个距离矩阵,您不需要任何其他东西。

np.sqrt(((series[:,None,:] - series)**2).sum(axis=2))