创建张量的欧氏距离矩阵

时间:2017-11-05 18:05:06

标签: python numpy matrix

我有10000个具有形状(32,32,3)的矩阵。我想在所有矩阵之间创建一个欧几里德距离矩阵。最后,它会像,

[0, d2, d3, d4, ...]
[d1, 0, d3, d4, ...]
[d1, d2, 0, d4, ...]
[d1, d2, d3, 0, ...]

如何以最快的方式制作它?我尝试了以下内容,但需要很长时间才能完成。

import numpy as np
dists = []
for a in range(len(X_test)):
    dists.append([])
    for b in range(len(X_test)):
        dists[a].append(np.linalg.norm(X_test[a] - X_test[b]))
print dists

2 个答案:

答案 0 :(得分:2)

您可以利用距离矩阵对称的事实将时间缩短一半,并且只使用

计算上三角形部分
for b in range(a+1, len(X_test)):

第5行。

我没有看到任何其他明显的优化,同时保持问题完全相同,但似乎您正在使用三通道格式的32x32图像。那个3072维度!为什么不首先下采样到4x4,转换为HSL颜色空间,并且只保留Hue和Lightness以获得(4,4,2)"签名"对于每个图像。如果您的问题主要与形状有关,那么您也可以扔掉Hue,基本上可以使用黑白图像。

(4,4,2)只有32个维度,与(32,32,3)相比节省100。如果您确实想在(32,32,3)空间中进行完全比较,则只能在(4,4,2)空间中已经非常相似的图像上执行此操作。

答案 1 :(得分:2)

我已阅读Divakar comment

我问自己“这个pdist / cdist的东西是什么?”而不是问“给我演示Divakar”。 - 我读到了pdistnorm,我发现了以下代码

导入内容:

In [1]: import numpy as np
In [2]: from scipy.spatial.distance import pdist

生成随机样本,不一定与OP的样本一样大,并根据Divakar的建议对其进行重塑

In [3]: a = np.random.random((100,32,32,3))
In [4]: b = a.reshape((100,32*32*3))

使用IPython的magic,让我们对这两种方法进行基准测试

In [5]: %%timeit
   ...: dists = []
   ...: for i in range(len(a)):
   ...:     dists.append([])
   ...:     for j in range(len(a)):
   ...:         dists[i].append(np.linalg.norm(a[i] - a[j]))
128 ms ± 337 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [6]: %timeit pdist(b)
12.3 ms ± 252 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
Divakar的速度提高了1个数量级 - 但准确度又如何呢? 让我们重复计算......

In [7]: dists1 = []
   ...: for i in range(len(a)):
   ...:     dists1.append([])
   ...:     for j in range(len(a)):
   ...:         dists1[i].append(np.linalg.norm(a[i] - a[j]))
In [8]: dists2 = pdist(b)

为了比较结果,我们必须意识到pdist只计算距离方矩阵的上三角(因为矩阵是对称的,而主对角线同样等于零)所以我们必须小心在检查我们的结果时:因此我使用allclose

检查dists1的第一行的非对角线部分以及dists2的前99个元素
In [9]: np.allclose(dists1[0][1:], dists2[:99])
Out[9]: True

结果是一样的,很好。

估算10,000个元素所需的时间怎么样?感觉就是二次方,但让我们试验加倍元素的数量

In [10]: b = np.random.random((200,32*32*3))
In [11]: %timeit pdist(b)
48 ms ± 97.7 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [12]: 

新的时间是初始时间的4倍,所以我的计算量,在我的微软电脑和使用Divakar的提议上的估计是12ms x 100 x 100 = 120,000ms = 120s。您应该the excellent answer仔细阅读olooney并确定您真正想做的事情。