具有非标量输出的Numpy向量化函数

时间:2017-11-19 07:45:29

标签: python numpy

我正在尝试对输出列表的函数进行矢量化。我希望从numpy列表中提取所有值并让它返回一个矩阵,这样每行都是输入向量中元素的输出。

import numpy as np

def func(x, n):
    o = []
    for i in range(n):
        o.append(x+i)
    return o

vec_func = np.vectorize(func)
matrix = vec_func(np.asarray([0, 1, 2]), 10)

然而我收到了错误

  

ValueError:使用序列设置数组元素。

我该如何解决这个问题?

1 个答案:

答案 0 :(得分:3)

frompyfunc可能会更好:

In [525]: def fun(x):
     ...:     return x+.1, x+.2, x+.3
     ...: 

我指定1个输入,3个输出值。它返回dtype对象:

In [526]: np.frompyfunc(fun,1,3)(np.arange(5))
Out[526]: 
(array([0.1, 1.1, 2.1, 3.1, 4.1], dtype=object),
 array([0.2, 1.2, 2.2, 3.2, 4.2], dtype=object),
 array([0.3, 1.3, 2.3, 3.3, 4.3], dtype=object))

这是3个数组的元组。它们可以与stack

一起转换为一个二维数组
In [527]: np.stack(_, 1)
Out[527]: 
array([[0.1, 0.2, 0.3],
       [1.1, 1.2, 1.3],
       [2.1, 2.2, 2.3],
       [3.1, 3.2, 3.3],
       [4.1, 4.2, 4.3]], dtype=object)

我可以使用astype(float)进一步采取步骤。

我当然认为这是一个玩具功能。对于这个简单的事情,不需要使用vectorize

In [528]: fun(np.arange(5))
Out[528]: 
(array([ 0.1,  1.1,  2.1,  3.1,  4.1]),
 array([ 0.2,  1.2,  2.2,  3.2,  4.2]),
 array([ 0.3,  1.3,  2.3,  3.3,  4.3]))

所有vectorize需要的是otypes参数:

In [536]: np.vectorize(fun, otypes='ddd')(np.arange(5))
Out[536]: 
(array([ 0.1,  1.1,  2.1,  3.1,  4.1]),
 array([ 0.2,  1.2,  2.2,  3.2,  4.2]),
 array([ 0.3,  1.3,  2.3,  3.3,  4.3]))

如果函数返回数组而不是元组或列表,我们可以使用signature

In [546]: def fun(x):
     ...:     return np.array([x+.1, x+.2, x+.3])

In [547]: np.vectorize(fun, signature='()->(n)')(np.arange(5))
Out[547]: 
array([[ 0.1,  0.2,  0.3],
       [ 1.1,  1.2,  1.3],
       [ 2.1,  2.2,  2.3],
       [ 3.1,  3.2,  3.3],
       [ 4.1,  4.2,  4.3]])

或者使用原始元组/列表大小写,将其包装在lambda np.vectorize(lambda x:np.array(fun(x)), signature='()->(n)')

经验表明frompyfunc方法最快。带有otypes的vectorize有点慢(但它使用frompyfunc)。 signature是更新的方法,使用不同的代码,速度稍慢。

使用新的funcsignature方法仍然有效。我添加了excluded,因此它不会尝试broadcast n参数:

In [553]: np.vectorize(lambda x,n:np.array(func(x,n)), signature='()->(n)',excluded=[1])(np.arange(5),3)
Out[553]: 
array([[0, 1, 2],
       [1, 2, 3],
       [2, 3, 4],
       [3, 4, 5],
       [4, 5, 6]])
In [554]: np.vectorize(lambda x,n:np.array(func(x,n)), signature='()->(n)',excluded=[1])(np.arange(5),7)
Out[554]: 
array([[ 0,  1,  2,  3,  4,  5,  6],
       [ 1,  2,  3,  4,  5,  6,  7],
       [ 2,  3,  4,  5,  6,  7,  8],
       [ 3,  4,  5,  6,  7,  8,  9],
       [ 4,  5,  6,  7,  8,  9, 10]])