【问题标题】:Numpy Vectorize SignatureNumpy 矢量化签名
【发布时间】:2020-03-24 13:58:18
【问题描述】:

问题陈述

我必须有两个数组(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 循环,因为我打算将此函数应用于一些大型矩阵

【问题讨论】:

  • 嘿 Armand,我没有看到与初级编程相关的问题。 FMPOV 这个问题在math.stackexchange.com@ 提问时会有更多机会得到回答
  • 谢谢文森,我也会在那里发帖的。
  • 你为什么要使用vectorize?它不会提高速度。签名功能甚至更慢。它不会避免循环。阅读其免责声明
  • vectorize 使用numpy 广播,与arr1 + arr2 使用的规则相同。使用正确的维度组合,您可以对成对的行进行操作。但是....
  • @hpaulj 谢谢,我错过了文档中的那部分。您是否还有其他一些指导,比如我可以如何解决这个问题或者循环是最好的解决方案?

标签: python numpy vectorization


【解决方案1】:

您可以使用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.]])

这种适当“矢量化”方法的一个缺点是广播的差异可能会变得非常大,并导致内存错误。

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

scipy.spatial.distance.pdist 是进行成对距离的好工具。

【讨论】:

  • 感谢@hpaulj,这对我很有帮助,并给了我一些新的东西,我可以去阅读!谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-03-17
  • 1970-01-01
  • 2021-04-27
  • 2020-04-06
  • 1970-01-01
  • 1970-01-01
  • 2015-03-30
相关资源
最近更新 更多