【问题标题】:Numpy vectorize signature definition - ValueErrorNumpy矢量化签名定义 - ValueError
【发布时间】:2019-03-05 19:30:46
【问题描述】:

我正在尝试使用 Python/Numpy 矢量化函数来减少 for 循环。

我的函数调用如下所示

out_vectors = v_calculation(
                            in_vectors,
                            p
)

向量化函数定义为

v_calculation = np.vectorize(
                     my_calculation,
                     signature='(j,i),(i)->()'
)

in_vectors 是一个形状数组

(3,6,200,3)

但是前两个维度 (3,6) 可以是任何东西。这些是循环尺寸。

p 是一个形状数组

(3,)

我的计算是这样的

def my_calculation(in_vector, p):
    """
    total magnetic field from Biot-Savart's law
    """
    out_vector = np.zeros((3,))

    l_vector = in_vector[1:, :] - in_vector[:-1, :]
    r_vector = (in_vector[:-1, :] + l_vector / 2) - p

    out_vector = np.sum(np.cross(l_vector, r_vector) / \
                        np.linalg.norm(r_vector) ** 3,
                        axis=0
    )

    return out_vector

在这个函数中,in_vector 是一个形状为 (200, 3) 的数组,p 是相同的形状 (3,)。 out_vector 形状为 (3,)。这是正确的。

out_vectors,向量化函数的结果应该是(6,3)。对于 input_vectors 的每个第二维(在本例中为 6),这应该是对 input_vectors 的第一维(在本例中为 3)求和的 my_calculation 的结果。结果的第二维是 3(向量的 x、y、z 分量),与 p 的维数和 input_vectors 的第四维相同。我希望这一切都清楚了。

我的代码在矢量化函数调用中失败

堆栈跟踪

~/path/to/my/code.py in calculate_vectors(mgr)
    588         out_vectors = v_calculation(
    589                                 in_vectors,
--> 590                                 p
    591         )

~/miniconda/lib/python3.7/site-packages/numpy/lib/function_base.py in __call__(self, *args, **kwargs)
   1970             vargs.extend([kwargs[_n] for _n in names])
   1971 
-> 1972         return self._vectorize_call(func=func, args=vargs)
   1973 
   1974     def _get_ufunc_and_otypes(self, func, args):

~/miniconda/lib/python3.7/site-packages/numpy/lib/function_base.py in _vectorize_call(self, func, args)
   2036         """Vectorized call to `func` over positional `args`."""
   2037         if self.signature is not None:
-> 2038             res = self._vectorize_call_with_signature(func, args)
   2039         elif not args:
   2040             res = func()

~/miniconda/lib/python3.7/site-packages/numpy/lib/function_base.py in _vectorize_call_with_signature(self, func, args)
   2100 
   2101             for output, result in zip(outputs, results):
-> 2102                 output[index] = result
   2103 
   2104         if outputs is None:

ValueError: setting an array element with a sequence.

【问题讨论】:

  • 快速评论 - np.vectorize 比更直接的迭代要慢。有了签名,它甚至更慢。所以使用它是为了方便,而不是速度。此外,我还没有看到或回答许多涉及signature 选项的问题。这是一个相对较新的功能。
  • 这个错误意味着output[index]output数组的一个元素槽,但是result是某种数组。这表明签名与您的功能不匹配。 (但我也没有检查过)。
  • np.array((3,)) 不创建形状 (3,) 数组。然而,这种说法是没有用的。我们不会在 Python 中提前“定义”变量。 out_vectornp.sum(...) 表达式中获取分配给它的值。
  • 哦,是的,这是真的。我的意思是使用 np.zeros 预先分配它。 stackoverflow.com/questions/33333683/… 显示使用预分配。我的印象是它很常用。不是吗?
  • 只有在使用 ufuncout 参数(如链接中所示)或进行索引分配时,您才进行预分配,例如output[i] = fun(i)a = np.zeros((3,)) 创建一个 3 元素数组。 output=... 为变量分配一个新对象,清除之前的所有分配。

标签: python numpy array-broadcasting numpy-ufunc


【解决方案1】:

这对我有用。请注意,我更改了返回签名,以匹配两个输入的共享最终维度。

In [54]: A = np.arange(12).reshape(4,3); b = np.arange(3)                       
In [55]: my_calculation(A,b)                                                    
Out[55]: array([0., 0., 0.])
In [56]: f = np.vectorize(my_calculation, signature='(j,i),(i)->(i)')           
In [57]: f(A,b)                                                                 
Out[57]: array([0., 0., 0.])
In [58]: f([A,A,A],b)                                                           
Out[58]: 
array([[0., 0., 0.],
       [0., 0., 0.],
       [0., 0., 0.]])

【讨论】:

  • 谢谢你。这完全像我想要的那样工作。我显然在考虑输出错误,因为我应该期待一个大小为 (3,6,3) 的数组。
猜你喜欢
  • 1970-01-01
  • 2021-04-06
  • 1970-01-01
  • 2018-03-17
  • 1970-01-01
  • 2021-04-27
  • 2020-04-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多