Numpy vectorize,使用列表作为参数

Hoo*_*ked 9 python numpy vectorization

numpy vectorize函数很有用,但是当函数参数是列表而不是标量时,它表现不佳.举个例子:

import numpy as np

def f(x, A):
    print "type(A)=%s, A=%s"%(type(A),A)
    return sum(A)/x

X = np.linspace(1,2,10)
P = [1,2,3]

f2 = np.vectorize(f)

f(X,P)
f2(X,P)
Run Code Online (Sandbox Code Playgroud)

得到:

type(A)=<type 'list'>, A=[1, 2, 3]
type(A)=<type 'numpy.int64'>, A=1

Traceback (most recent call last):
  File "vectorize.py", line 14, in <module>
    f2(X,P)
  File "/usr/local/lib/python2.6/dist-packages/numpy/lib/function_base.py", line 1824, in __call__
    theout = self.thefunc(*newargs)
  File "vectorize.py", line 5, in f
    return sum(A)/x
TypeError: 'numpy.int64' object is not iterable
Run Code Online (Sandbox Code Playgroud)

我知道函数f 没有vectorize它的情况下工作正常,但是我想知道如何(通常)向量化一个函数,该函数的参数采用列表而不是标量.

Gab*_*ant 11

你的问题没有清楚地说明你想从矢量化函数中看到什么输出,但是我假设你希望将相同的列表(A)作为参数应用于f()的每次调用(即一次对于X数组中的每个元素)

函数的矢量化版本确保所有参数都是数组,然后应用numpy的广播规则来确定如何组合这些参数.

与np.array包装np.ndarray一样,通过自动将列表转换为包含相同元素的数组,而不是使用包含列表的dtype = object的数组,对数组的参数的强制尝试会有所帮助.它唯一的元素.大部分时间这都是我们想要的,但在你的情况下,这种"聪明"的行为会回来咬你.

虽然可能有一种方法可以指示numpy仅将某些输入视为向量,但有两种直接的方法可以获得您所追求的行为:

  1. 手动创建一个dtype = object数组,以在广播规则中工作
  2. 咖喱值矢量化的功能之前

1. dtype = object

Numpy数组从仅存储一种类型的项目中获得效率,但它们仍然可以包含任意python对象,方法是指定存储的数据类型为python对象:

list_obj_array = np.ndarray((1,), dtype=object)
list_obj_array[0] = [1,2,3]
f2(X,list_obj_array)  # using your definition from above
Run Code Online (Sandbox Code Playgroud)

打印:

type(A)=<type 'list'>, A=[1, 2, 3]
type(A)=<type 'list'>, A=[1, 2, 3]
type(A)=<type 'list'>, A=[1, 2, 3]
type(A)=<type 'list'>, A=[1, 2, 3]
type(A)=<type 'list'>, A=[1, 2, 3]
type(A)=<type 'list'>, A=[1, 2, 3]
type(A)=<type 'list'>, A=[1, 2, 3]
type(A)=<type 'list'>, A=[1, 2, 3]
type(A)=<type 'list'>, A=[1, 2, 3]
type(A)=<type 'list'>, A=[1, 2, 3]
type(A)=<type 'list'>, A=[1, 2, 3]
Run Code Online (Sandbox Code Playgroud)

并返回:

array([ 6.        ,  5.4       ,  4.90909091,  4.5       ,  4.15384615,
        3.85714286,  3.6       ,  3.375     ,  3.17647059,  3.        ])
Run Code Online (Sandbox Code Playgroud)

2. Currying

由于您将相同的列表传递给数组中每个项的函数调用,因此您可以在应用矢量化之前通过currying直接存储列表:

def curry_f(A):
    def f_curried(x):
        return f(x, A)  # using your definition from above
    return f_curried

f2 = np.vectorize(curry_f(P))
f2(X)
Run Code Online (Sandbox Code Playgroud)

打印:

type(A)=<type 'list'>, A=[1, 2, 3]
type(A)=<type 'list'>, A=[1, 2, 3]
type(A)=<type 'list'>, A=[1, 2, 3]
type(A)=<type 'list'>, A=[1, 2, 3]
type(A)=<type 'list'>, A=[1, 2, 3]
type(A)=<type 'list'>, A=[1, 2, 3]
type(A)=<type 'list'>, A=[1, 2, 3]
type(A)=<type 'list'>, A=[1, 2, 3]
type(A)=<type 'list'>, A=[1, 2, 3]
type(A)=<type 'list'>, A=[1, 2, 3]
Run Code Online (Sandbox Code Playgroud)

并返回:

array([ 6.        ,  5.4       ,  4.90909091,  4.5       ,  4.15384615,
        3.85714286,  3.6       ,  3.375     ,  3.17647059,  3.        ])
Run Code Online (Sandbox Code Playgroud)

PS你可能也希望看一下np.frompyfunc - 它类似于vectorize(),但工作水平略低.