根据位置将函数应用于 numpy 矩阵

Apply function to numpy matrix dependent on position

给定一个形状为 [m,m] 的二维 numpy 数组 X,我希望应用一个函数并获得一个新的二维 numpy 矩阵 P,其形状也为 [m,m],其得到第[i,j]个元素如下:

P[i][j] = exp (-|| X[i] - x[j] ||**2)

其中 ||.|| 表示向量的标准 L-2 范数。有没有比简单的嵌套 for 循环更快的方法?

例如,

X = [[1,1,1],[2,3,4],[5,6,7]]

然后,在对角线上,访问的行将相同,并且它们的差异 norm/magnitude 将为 0。因此,

P[0][0] = P[1][1] = P[2][2] = exp (0) = 1.0

此外,

P[0][1] = exp (- || X[0] - X[1] ||**2) = exp (- || [-1,-2,-3] || ** 2) = exp (-14)

等等

使用嵌套 for 循环的最简单的解决方案如下:

import numpy as np
X = np.array([[1,2,3],[4,5,6],[7,8,9]])
P = np.zeros (shape=[len(X),len(X)])
for i in range (len(X)):
    for j in range (len(X)):
        P[i][j] = np.exp (- np.linalg.norm (X[i]-X[j])**2)
        
print (P)

这会打印:

P = [[1.00000000e+00 1.87952882e-12 1.24794646e-47]
    [1.87952882e-12 1.00000000e+00 1.87952882e-12]
    [1.24794646e-47 1.87952882e-12 1.00000000e+00]]

此处m为5e4量级。

如果您提供示例数组,这会更容易。您可以使用

创建大小为 [m, m, m] 的数组 Q,其中 Q[i, j, k] = X[i, k] - X[j, k]
X[None,:,:] - X[:,None,:]

此时,您正在对第三轴执行简单的 numpy 操作。

In [143]: X = np.array([[1,2,3],[4,5,6],[7,8,9]])
     ...: P = np.zeros (shape=[len(X),len(X)])
     ...: for i in range (len(X)):
     ...:     for j in range (len(X)):
     ...:         P[i][j] = np.exp (- np.linalg.norm (X[i]-X[j]))
     ...: 
In [144]: P
Out[144]: 
array([[1.00000000e+00, 5.53783071e-03, 3.06675690e-05],
       [5.53783071e-03, 1.00000000e+00, 5.53783071e-03],
       [3.06675690e-05, 5.53783071e-03, 1.00000000e+00]])

无循环版本:

In [145]: np.exp(-np.sqrt(((X[:,None,:]-X[None,:,:])**2).sum(axis=2)))
Out[145]: 
array([[1.00000000e+00, 5.53783071e-03, 3.06675690e-05],
       [5.53783071e-03, 1.00000000e+00, 5.53783071e-03],
       [3.06675690e-05, 5.53783071e-03, 1.00000000e+00]])

我不得不删除你的 **2 以匹配值。

norm 应用于 3d 差异数组:

In [148]: np.exp(-np.linalg.norm(X[:,None,:]-X[None,:,:], axis=2))
Out[148]: 
array([[1.00000000e+00, 5.53783071e-03, 3.06675690e-05],
       [5.53783071e-03, 1.00000000e+00, 5.53783071e-03],
       [3.06675690e-05, 5.53783071e-03, 1.00000000e+00]])

scikit 包之一(学习?)中有一个 cdist 可以更快地处理这类事情。

正如 hpaulj 提到的,cdist 做得更好。请尝试以下操作。

from scipy.spatial.distance import cdist
import numpy as np

np.exp(-cdist(X,X,'sqeuclidean'))

注意 sqeuclidean。这意味着 scipy 不取平方根,因此您不必像上面那样使用标准进行平方。