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)
给出:
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
我理解函数f在没有vectorize
的情况下很好但是我想知道如何(通常)向量化一个函数,该函数的参数在列表中取而代之而不是标量。
答案 0 :(得分:11)
你的问题并不清楚你想从矢量化函数中看到什么输出,但是我假设你希望将相同的列表(A)作为参数应用于f()的每次调用(即对于X阵列中的每个元素一次)
函数的矢量化版本确保所有参数都是数组,然后应用numpy's broadcasting rules来确定如何组合这些参数。
与np.array的np.ndarray包装一样,通过自动将列表转换为包含相同元素的数组,而不是使用包含dtype = object的数组,对数组的参数的强制尝试会有所帮助。列表作为其唯一元素。大部分时间这都是我们想要的,但在你的情况下,这种“聪明”的行为会回来咬你。
虽然可能有一种方法可以指示numpy只将某些输入视为向量,但有两种直接的方法来获得你所追求的行为:
<强> 1。 D型=对象强>
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
打印:
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]
并返回:
array([ 6. , 5.4 , 4.90909091, 4.5 , 4.15384615,
3.85714286, 3.6 , 3.375 , 3.17647059, 3. ])
<强> 2。讨好强>
由于您将相同的列表传递给数组中每个项目的函数调用,因此您可以在应用矢量化之前通过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)
打印:
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]
并返回:
array([ 6. , 5.4 , 4.90909091, 4.5 , 4.15384615,
3.85714286, 3.6 , 3.375 , 3.17647059, 3. ])
P.S。您可能还希望看一下np.frompyfunc - 它类似于vectorize(),但工作水平略低。
答案 1 :(得分:0)
这是一个递归装饰器的例子,我目前用它来矢量化一个以一维数组作为第一个参数的函数:
def broadcast(fvec):
def inner(vec, *args, **kwargs):
if len(vec.shape) > 1:
return np.array([inner(row, *args, **kwargs) for row in vec])
else:
return fvec(vec, *args, **kwargs)
return inner
我猜它与np.vectorize
几乎完全相同,但我使用它比试图使vectorize
/ frompyfunc
适应这项工作更容易。