为什么 numpy.vectorize() 改变标量函数的除法输出?

Pau*_*eux 1 python numpy division

当我用 numpy 对函数进行向量化时,我得到了一个奇怪的结果。

import numpy as np
def scalar_function(x, y):
    """ A function that returns x*y if x<y and x/y otherwise
    """
    if x < y :
        out = x * y 
    else:
        out = x/y 
    return out

def vector_function(x, y):
    """
    Make it possible to accept vectors as input
    """
    v_scalar_function = np.vectorize(scalar_function)
    return v_scalar_function(x, y)
Run Code Online (Sandbox Code Playgroud)

我们确实有

scalar_function(4,3)
# 1.3333333333333333
Run Code Online (Sandbox Code Playgroud)

为什么矢量化版本会给出这种奇怪的输出?

vector_function(np.array([3,4]), np.array([4,3]))
[12  1]
Run Code Online (Sandbox Code Playgroud)

虽然对矢量化版本的调用工作正常:

vector_function(np.array([4,4]), np.array([4,3]))
[1.         1.33333333]
Run Code Online (Sandbox Code Playgroud)

阅读numpy.divide

注释 Python 2.2 中添加了向下除法运算符 //,使 // 和 / 等效于运算符。/ 的默认楼层除法操作可以用 from import 除法替换为 true 除法__future__。在Python 3.0中,//是下限除法运算符,/是真正的除法运算符。true_divide(x1, x2) 函数相当于 Python 中的真除法。

让我觉得这可能是与 python2 相关的遗留问题?但我使用的是Python 3!

rog*_*osh 6

状态文档numpy.vectorize

除非指定,否则输出类型通过评估输入的第一个元素来确定

由于您没有指定返回数据类型,并且第一个示例是整数乘法,因此第一个数组也是整数类型并对值进行舍入。相反,当第一个操作是除法时,数据类型会自动向上转换为浮点型。您可以通过指定 dtype 来修复代码vector_function(对于此问题,该 dtype 不一定必须与 64 位一样大):

def vector_function(x, y):
    """
    Make it possible to accept vectors as input
    """
    v_scalar_function = np.vectorize(scalar_function, otypes=[np.float64])
    return v_scalar_function(x, y)
Run Code Online (Sandbox Code Playgroud)

另外,您还应该从相同的文档中注意到,它numpy.vectorize是一个便利函数,基本上只是包装了一个 Pythonfor循环,因此在提供任何实际性能增益的意义上并不是矢量化的。

对于这样的二元选择,更好的整体方法是:

def vectorized_scalar_function(arr_1, arr_2):
    return np.where(arr_1 < arr_2, arr_1 * arr_2, arr_1 / arr_2)

print(vectorized_scalar_function(np.array([4,4]), np.array([4,3])))
print(vectorized_scalar_function(np.array([3,4]), np.array([4,3])))
Run Code Online (Sandbox Code Playgroud)

上面的速度应该快几个数量级,并且(可能是巧合,而不是依赖硬性规则)不会遇到结果的类型转换问题。