Numpy向量化,使用列表作为参数

时间:2022-12-28 04:17:41

The numpy vectorize function is useful, but it doesn't behave well when the function arguments are lists rather then scalars. As an example:

numpy矢量化函数是有用的,但是当函数参数是列表而不是标量时,它的行为就不是很好。作为一个例子:

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)

Gives:

给:

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

I understand that the function f works just fine without vectorizeing it, but I'd like to know how to (in general) vectorize a function whose arguments take in lists rather than a scalar.

我知道函数f在没有向量化的情况下可以很好地工作,但是我想知道如何(通常)向向量化一个函数,它的参数是列表而不是标量。

2 个解决方案

#1


11  

Your question doesn't make clear precisely what output you would like to see from the vectorized function, but I'm going to assume you would like the same list (A) applied as an argument to every invocation of f() (ie once for each element in the X array)

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

The vectorized version of a function ensures all arguments are arrays, and then applies numpy's broadcasting rules to determine how these arguments should be combined.

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

As with np.array's wrapping of np.ndarray, the coercion of the arguments to arrays tries to be helpful, by automatically converting a list to an array containing the same elements, rather than making an array with dtype=object that contains the list as its sole element. Most of the time this is what we want, but in your case, this "smart" behaviour is coming back to bite you.

与np。数组的包装np。ndarray,参数对数组的强制要求是有帮助的,方法是自动将列表转换为包含相同元素的数组,而不是使用dtype=object创建一个数组,该数组将列表作为其惟一元素。大多数时候,这是我们想要的,但在你的情况下,这种“聪明”的行为会反过来伤害你。

While there may be a way to instruct numpy to only treat certain inputs as vectors, there are two straightforward ways to get the behaviour you're after:

虽然有一种方法可以指示numpy只把某些输入当作向量,但是有两种直接的方法可以得到您所追求的行为:

  1. Manually create an array with dtype=object to work within the broadcasting rules
  2. 使用dtype=object手动创建一个数组以在广播规则中工作
  3. Curry the value prior to vectorizing the function
  4. 在向量化函数之前对值进行Curry处理

1. dtype=object

1。dtype =对象

Numpy arrays derive their efficiency from only storing one type of item, but they can still contain arbitrary python objects by specifying that the stored data type be python objects:

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

prints:

打印:

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]

and returns:

并返回:

array([ 6.        ,  5.4       ,  4.90909091,  4.5       ,  4.15384615,
        3.85714286,  3.6       ,  3.375     ,  3.17647059,  3.        ])

2. Currying

2。局部套用

Since you are passing the same list to the function call for each item in the array, you can store the list directly with the function by currying before applying vectorization:

由于您正在将相同的列表传递给数组中的每个项的函数调用,所以可以在应用矢量化之前,通过对列表进行收缩,将列表直接存储到函数中:

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)

prints:

打印:

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]

and returns:

并返回:

array([ 6.        ,  5.4       ,  4.90909091,  4.5       ,  4.15384615,
        3.85714286,  3.6       ,  3.375     ,  3.17647059,  3.        ])

P.S. you may also wish to have a look at np.frompyfunc -- it is similar to vectorize(), but works at a slightly lower level.

另外,您可能还希望了解一下np.frompyfunc——它类似于vectorize(),但工作级别稍低一些。

#2


0  

This is an example of a recursive decorator I'm currently using to vectorize a function that takes a 1D array as the first argument:

这是我现在使用的递归装饰器的一个例子,这个函数将一维数组作为第一个参数:

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

I guess it does pretty much the same as np.vectorize, but it turned out easier for me to use this than try to adapt vectorize/frompyfunc for the job.

我猜它和np差不多。vectorize,但是对我来说,它比尝试使用vectorize/frompyfunc来完成这项工作要容易得多。

#1


11  

Your question doesn't make clear precisely what output you would like to see from the vectorized function, but I'm going to assume you would like the same list (A) applied as an argument to every invocation of f() (ie once for each element in the X array)

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

The vectorized version of a function ensures all arguments are arrays, and then applies numpy's broadcasting rules to determine how these arguments should be combined.

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

As with np.array's wrapping of np.ndarray, the coercion of the arguments to arrays tries to be helpful, by automatically converting a list to an array containing the same elements, rather than making an array with dtype=object that contains the list as its sole element. Most of the time this is what we want, but in your case, this "smart" behaviour is coming back to bite you.

与np。数组的包装np。ndarray,参数对数组的强制要求是有帮助的,方法是自动将列表转换为包含相同元素的数组,而不是使用dtype=object创建一个数组,该数组将列表作为其惟一元素。大多数时候,这是我们想要的,但在你的情况下,这种“聪明”的行为会反过来伤害你。

While there may be a way to instruct numpy to only treat certain inputs as vectors, there are two straightforward ways to get the behaviour you're after:

虽然有一种方法可以指示numpy只把某些输入当作向量,但是有两种直接的方法可以得到您所追求的行为:

  1. Manually create an array with dtype=object to work within the broadcasting rules
  2. 使用dtype=object手动创建一个数组以在广播规则中工作
  3. Curry the value prior to vectorizing the function
  4. 在向量化函数之前对值进行Curry处理

1. dtype=object

1。dtype =对象

Numpy arrays derive their efficiency from only storing one type of item, but they can still contain arbitrary python objects by specifying that the stored data type be python objects:

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

prints:

打印:

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]

and returns:

并返回:

array([ 6.        ,  5.4       ,  4.90909091,  4.5       ,  4.15384615,
        3.85714286,  3.6       ,  3.375     ,  3.17647059,  3.        ])

2. Currying

2。局部套用

Since you are passing the same list to the function call for each item in the array, you can store the list directly with the function by currying before applying vectorization:

由于您正在将相同的列表传递给数组中的每个项的函数调用,所以可以在应用矢量化之前,通过对列表进行收缩,将列表直接存储到函数中:

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)

prints:

打印:

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]

and returns:

并返回:

array([ 6.        ,  5.4       ,  4.90909091,  4.5       ,  4.15384615,
        3.85714286,  3.6       ,  3.375     ,  3.17647059,  3.        ])

P.S. you may also wish to have a look at np.frompyfunc -- it is similar to vectorize(), but works at a slightly lower level.

另外,您可能还希望了解一下np.frompyfunc——它类似于vectorize(),但工作级别稍低一些。

#2


0  

This is an example of a recursive decorator I'm currently using to vectorize a function that takes a 1D array as the first argument:

这是我现在使用的递归装饰器的一个例子,这个函数将一维数组作为第一个参数:

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

I guess it does pretty much the same as np.vectorize, but it turned out easier for me to use this than try to adapt vectorize/frompyfunc for the job.

我猜它和np差不多。vectorize,但是对我来说,它比尝试使用vectorize/frompyfunc来完成这项工作要容易得多。