矢量化函数无法评估

Vectorized function fails to evaluate

我在使用矢量化函数时遇到问题:

def func(y):
    return sum(x**(-y) for x in range(1, 10))
vect_func = np.vectorize(func)
vect_func([1, 2, 3, 4, 5])

# Output:
# ValueError: Integers to negative integer powers are not allowed.

而以下工作正常:

[func(t) for t in [1, 2, 3, 4, 5]]

# Output:
# [2.8289682539682537, 1.5397677311665408, 1.1965319856741932, 1.0819365834937567, 1.0368973413446938]

是否可以让 np.vectorize 处理此示例?

当函数在 np.vectorize 中不起作用时,最好验证参数是什么。

让我们在函数中添加一个 type 打印:

In [36]: def func(y):
    ...:     print(type(y))
    ...:     return sum(x**(-y) for x in range(1, 10))
    ...: 

在列表理解中,Python int 被传递:

In [37]: func(3)
<class 'int'>
Out[37]: 1.1965319856741932

使用 vectorized 版本:

In [40]: vect_func(3)
<class 'numpy.int64'>
Traceback (most recent call last):
  File "<ipython-input-40-65e2816d8003>", line 1, in <module>
    vect_func(3)
  File "/usr/local/lib/python3.8/dist-packages/numpy/lib/function_base.py", line 2163, in __call__
    return self._vectorize_call(func=func, args=vargs)
  File "/usr/local/lib/python3.8/dist-packages/numpy/lib/function_base.py", line 2241, in _vectorize_call
    ufunc, otypes = self._get_ufunc_and_otypes(func=func, args=args)
  File "/usr/local/lib/python3.8/dist-packages/numpy/lib/function_base.py", line 2201, in _get_ufunc_and_otypes
    outputs = func(*inputs)
  File "<ipython-input-36-311d525a60ba>", line 3, in func
    return sum(x**(-y) for x in range(1, 10))
  File "<ipython-input-36-311d525a60ba>", line 3, in <genexpr>
    return sum(x**(-y) for x in range(1, 10))
ValueError: Integers to negative integer powers are not allowed.

y 不是 python int,它是 numpy 整数。

In [41]: func(np.int64(3))
<class 'numpy.int64'>
Traceback (most recent call last):
  File "<ipython-input-41-c34830937ffd>", line 1, in <module>
    func(np.int64(3))
  File "<ipython-input-36-311d525a60ba>", line 3, in func
    return sum(x**(-y) for x in range(1, 10))
  File "<ipython-input-36-311d525a60ba>", line 3, in <genexpr>
    return sum(x**(-y) for x in range(1, 10))
ValueError: Integers to negative integer powers are not allowed.

如果我们故意传递 Python int 它有效:

In [42]: vect_func(np.array([1,2,3], object))
<class 'int'>
<class 'int'>
<class 'int'>
<class 'int'>
Out[42]: array([2.82896825, 1.53976773, 1.19653199])

np.vectorize 在将多个数组传递给标量函数时非常方便,并且您想利用 broadcasting。但是对于列表或可以压缩的列表,它不会增加列表理解的任何内容——甚至速度也不行。

如本案例所示,它有一些新手(甚至更有经验的用户)无法捕捉到的陷阱。这是输入的性质。对于许多其他 SO 问题,它是 return 值的性质(自动 otypes)。