【问题标题】:numpy.vectorize function signaturenumpy.vectorize 函数签名
【发布时间】:2021-11-30 07:27:20
【问题描述】:

我有 2 个数组:

>>> a.shape
(9, 3, 11)
>>> b.shape
(9,)

我想计算c[i, j] = f(a[i, j, :], b[i]) 的等价物,其中f(a0, b0) 是一个带有len(a0) == 11len(b0) == 9 两个参数的函数。这里,i 正在迭代 range(9)j 正在迭代 range(3)

有没有办法使用numpy.vectorize 对此进行编码?还是通过一些巧妙的广播更简单?

我已经尝试了 2 个小时,但我只是不明白如何使它工作......我尝试广播或使用签名但无济于事。

【问题讨论】:

  • np.array([f(a[i,j,:], b[i]) for j in range(3)] for i in range(9)])a + b[:,None,None] 会起作用,但结果是 (9,3,11)。或者np.sum(a + b[:,None,None]).axis=2),如果你想(9,3),但你也可以先np.sum(a, axis=2)
  • np.vectorize 在默认模式下将标量值传递给函数。有一个signature 选项可以让它传递数组,但使用起来更棘手,甚至更慢。 apply_along_axis 可以迭代ai,j 维度(缓慢),但它不能同时迭代b。它只是一个数组迭代器。嵌套列表推导式可能是您的最佳选择。
  • 函数示例可能会有所帮助。您还需要明确函数返回的内容。它是标量吗,所以 c 可以是数字 dtype 数组。我认为这需要对 11 号尺寸进行某种缩减。
  • @hpaulj,最后我可以找到解决方案:np.vectorize(f, signature="(k),(1)->()") 然后我必须像f(a, b[:, None, None] 一样称呼它。你认为这会比循环慢得多吗?

标签: python numpy array-broadcasting numpy-ufunc


【解决方案1】:

最后,我可以让它像这样工作:

>>> f = np.vectorize(f, signature="(k),(1)->()")
>>> print(a.shape)
(9, 3, 11)
>>> print(b.shape)
(9,)
>>> print(f(a, b[:, None, None]).shape)
(9, 3)

这可确保f 以正确的形状被调用并正确迭代。坦率地说,从 Numpy 文档中了解为此目的在签名中使用 (1) 的技巧并不简单。

【讨论】:

    【解决方案2】:

    numpy.apply_along_axis 是您所需要的。

    import numpy as np
    
    a = np.ones( (9,3,11) )
    b = np.ones( 9 )
    
    def f(a0, b0):
        return sum(a0[:9]+b0)
    
    c = np.apply_along_axis( f, 2, a, b )
    print(c)
    

    c 的形状是 (9,3)。

    【讨论】:

    • 我得到一个 (9, 3, 9) 形状的c
    • OK,f 需要返回一个值。不是 9 的列表。现在 c 是 (9,3)。
    • 你可以只使用return np.sum(a0) + b0,所以我们不需要函数定义中的索引!重要的是返回标量值。
    • 那行不通,因为b0 是一个由 9 组成的数组。它将进行标量加法并返回一个列表,这就是我最终得到 (9,3,9) 的方式第一名。但是,我只是编造了那个虚拟功能,因为你没有提供你的。我想你的有点复杂。
    猜你喜欢
    • 1970-01-01
    • 2021-05-02
    • 2018-07-25
    • 1970-01-01
    • 1970-01-01
    • 2018-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多