Python中相似度矩阵的高效计算(NumPy)

nul*_*tto 4 python performance numpy similarity vectorization

X是一个Bxn numpy矩阵,即

import numpy as np
B = 10
n = 2
X = np.random.random((B, n))
Run Code Online (Sandbox Code Playgroud)

现在,我有兴趣计算所谓的内核(甚至是相似性)矩阵K,它具有形状BxB,其{i,j}第_ 个元素如下:

K(i,j)= fun(x_i,x_j)

其中x_t表示t矩阵的行第X并且fun是一些功能x_i,x_j.例如,这个函数可以是所谓的RBF函数,即

K(i,j)= exp( - | x_i - x_j | ^ 2).

为此,一种天真的方式如下:

K = np.zeros((B, B))
for i in range(X.shape[0]):
    x_i = X[i, :]
    for j in range(X.shape[0]):
        x_j = X[j, :]
        K[i, j] = np.exp(-np.linalg.norm(x_i - x_j, 2) ** 2)
Run Code Online (Sandbox Code Playgroud)

我想要的是以矢量化的方式进行上述操作,以提高效率.你能帮忙吗?

kaz*_*ase 6

如果你利用广播的力量,这当然可以单独使用numpy .

您只需以矢量化方式编写内部距离范数计算:

X1 = X[:, np.newaxis, :]
X2 = X[np.newaxis, :, :]
K = np.exp(-np.sum((X1 - X2)**2, axis=-1))
Run Code Online (Sandbox Code Playgroud)


max*_*111 5

不要矢量化它,只需编译它

这几乎每次都更快,代码更容易阅读。由于像Numba这样好的 jit 编译器,所以这是一件非常简单的事情。

在你的情况下:

import numpy as np
import numba as nb
@nb.njit(fastmath=True)
def Test_1(X):
  K = np.zeros((B, B))
  for i in range(X.shape[0]):
      x_i = X[i, :]
      for j in range(X.shape[0]):
          x_j = X[j, :]
          K[i, j] = np.exp(-np.linalg.norm(x_i - x_j, 2) ** 2)

  return K
Run Code Online (Sandbox Code Playgroud)

并行化函数也很容易:

import numpy as np
import numba as nb
@nb.njit(fastmath=True,parallel=True)
def Test_1(X):
  K = np.zeros((B, B))
  for i in nb.prange(X.shape[0]):
      x_i = X[i, :]
      for j in range(X.shape[0]):
          x_j = X[j, :]
          K[i, j] = np.exp(-np.linalg.norm(x_i - x_j, 2) ** 2)

  return K
Run Code Online (Sandbox Code Playgroud)

这很容易胜过迄今为止提供的所有其他解决方案。第一次函数调用需要大约 0.5 秒的时间,因为这里编译了您的代码,但我猜您想多次调用此函数。

如果使用单线程版本,还可以缓存编译结果。多线程代码的缓存可能很快就会实现。


Giu*_*ora 3

我不确定你是否可以仅使用 numpy 来解决这个问题。我会使用 scipy 库中的cdist方法,如下所示:

import numpy as np 
from scipy.spatial.distance import cdist
B=5
X=np.random.rand(B*B).reshape((B,B))
dist = cdist(X, X, metric='euclidean')
K = np.exp(dist)

dist
array([[ 0.        ,  1.2659804 ,  0.98231231,  0.80089176,  1.19326493],
       [ 1.2659804 ,  0.        ,  0.72658078,  0.80618767,  0.3776364 ],
       [ 0.98231231,  0.72658078,  0.        ,  0.70205336,  0.81352455],
       [ 0.80089176,  0.80618767,  0.70205336,  0.        ,  0.60025858],
       [ 1.19326493,  0.3776364 ,  0.81352455,  0.60025858,  0.        ]])
K
array([[ 1.        ,  3.5465681 ,  2.67062441,  2.22752646,  3.29783084],
       [ 3.5465681 ,  1.        ,  2.06799756,  2.23935453,  1.45883242],
       [ 2.67062441,  2.06799756,  1.        ,  2.01789192,  2.25584482],
       [ 2.22752646,  2.23935453,  2.01789192,  1.        ,  1.82259002],
       [ 3.29783084,  1.45883242,  2.25584482,  1.82259002,  1.        ]])
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助你。干得好

编辑您也可以仅使用 numpy 数组来实现 theano :

dist = (X ** 2).sum(1).reshape((X.shape[0], 1)) + (X ** 2).sum(1).reshape((1, X.shape[0])) - 2 * X.dot(X.T)
Run Code Online (Sandbox Code Playgroud)

应该是工作吧!