Numpy 向量化签名

Numpy Vectorize Signature

问题陈述

我必须分别有两个数组(XY)维度 (n,d)(m,d),并且想对两个矩阵。我要应用的功能如下:

def norm(x, y):
    return np.linalg.norm(x-y)

其中 xy 是不同矩阵对应的行向量。 我正在寻找的输出是一个形状为 (n,m) 的矩阵,其中每个索引是 XY.

中相应行向量之间差异的范数

预期解:

因此,如果输入矩阵是:

X = [[1,1,1,1],
    [2,2,2,2]]

Y = [[3,3,3,3],
    [4,4,4,4]]

我想获得以下输出:

[[4,6],
[2,4]]

当前解决方案

在这个阶段,我得到的唯一解决方案是使用 np.vectorize 函数对我的函数进行矢量化并将不同的行映射到函数并获得矩阵输出。但是,当对函数应用以下矢量化时:

norm_vec = np.vectorize(norm, signature='(d),(d)->()')

我得到以下输出:

[[4,4]]

看来该函数仅将函数映射到每对行而不是每行组合。 我对 vectorize 函数还是很陌生,我不确定 signature 参数是如何工作的,但我的直觉告诉我,这个具有正确签名的函数可以通过某种方式为我提供正确的解决方案.

是否有人可以让我更深入地了解 np.vectorize 函数的工作原理并构建正确的 signature 以获得我想要的解决方案,或者指出我正确的方向方向,如果我完全偏离轨道。我想避免使用 for 循环,因为我打算在一些大矩阵上应用这个函数

您使用signature没问题;它只需要使用 broadcasting:

In [374]: def norm(x, y): 
     ...:     return np.linalg.norm(x-y) 
     ...:                                                                                      

In [376]: f = np.vectorize(norm, signature='(d),(d)->()')                                      
In [377]:                                                                                      
In [377]: X = np.array([[1,1,1,1], 
     ...:     [2,2,2,2]]) 
     ...:  
     ...: Y = np.array([[3,3,3,3], 
     ...:     [4,4,4,4]])                                                                      
In [378]: f(X,Y)                                                                               
Out[378]: array([4., 4.])

In [379]: f(X[:,None,:], Y[None,:,:])                                                           
Out[379]: 
array([[4., 6.],
       [2., 4.]])

您的函数首先执行 x-y;所以让我们专注于此:

In [383]: f = np.vectorize(lambda x,y:x-y, signature='(d),(d)->(d)')                           
In [384]: f(X[:,None,:], Y[None,:,:])                                                           
Out[384]: 
array([[[-2, -2, -2, -2],
        [-3, -3, -3, -3]],

       [[-1, -1, -1, -1],
        [-2, -2, -2, -2]]])

但我们不需要 vectorize 来执行此操作:

In [385]: X[:,None,:]-Y[None,:,:]                                                              
Out[385]: 
array([[[-2, -2, -2, -2],
        [-3, -3, -3, -3]],

       [[-1, -1, -1, -1],
        [-2, -2, -2, -2]]])

norm 接受一个 axis 参数;指定最后一个,给出与 vectorize:

进行逐行计算相同的结果
In [387]: np.linalg.norm(X[:,None,:]-Y[None,:,:], axis=-1)                                     
Out[387]: 
array([[4., 6.],
       [2., 4.]])

这种正确 'vectorized' 方法的缺点是广播差异可能会变得非常大,并导致内存错误。

所以 np.vectorize 在函数不能使用更快的编译全数组方法时有些用处。但它不是一个速度工具。它比更明确的迭代要慢。 signature 添加很有趣,但更慢。

scipy.spatial.distance.pdist 是计算成对距离的好工具。