Python 在返回向量的函数上使用Numpy Vectorize

Python 在返回向量的函数上使用Numpy Vectorize,python,arrays,numpy,vectorization,Python,Arrays,Numpy,Vectorization,numpy.vectorize接受函数f:a->b并将其转换为g:a[]->b[] 当a和b都是标量时,这很好,但我想不出为什么它不能将b作为ndarray或列表使用,即f:a->b[]和g:a[]->b[] 例如: import numpy as np def f(x): return x * np.array([1,1,1,1,1], dtype=np.float32) g = np.vectorize(f, otypes=[np.ndarray]) a = np.arange(4)

numpy.vectorize
接受函数f:a->b并将其转换为g:a[]->b[]

a
b
都是标量时,这很好,但我想不出为什么它不能将b作为
ndarray
或列表使用,即f:a->b[]和g:a[]->b[]

例如:

import numpy as np
def f(x):
    return x * np.array([1,1,1,1,1], dtype=np.float32)
g = np.vectorize(f, otypes=[np.ndarray])
a = np.arange(4)
print(g(a))
这将产生:

array([[ 0.  0.  0.  0.  0.],
       [ 1.  1.  1.  1.  1.],
       [ 2.  2.  2.  2.  2.],
       [ 3.  3.  3.  3.  3.]], dtype=object)
好的,这给出了正确的值,但数据类型错误。更糟糕的是:

g(a).shape
收益率:

(4,)
所以这个数组是非常无用的。我知道我可以通过以下方式转换:

np.array(map(list, a), dtype=np.float32)
给我想要的:

array([[ 0.,  0.,  0.,  0.,  0.],
       [ 1.,  1.,  1.,  1.,  1.],
       [ 2.,  2.,  2.,  2.,  2.],
       [ 3.,  3.,  3.,  3.,  3.]], dtype=float32)
但这既不是有效的,也不是有益的。你们有谁能找到更干净的方法吗


提前谢谢

矢量化只是一个方便的功能。实际上没有。如果使用
np.vectorize
不方便,只需编写自己的函数即可

np.vectorize
的目的是将不支持numpy的函数(例如,将浮点作为输入,返回浮点作为输出)转换为可以在numpy数组上操作(并返回)的函数

您的函数
f
已经是numpy感知的——它在定义中使用numpy数组并返回numpy数组。因此
np.vectorize
不适合您的用例

因此,解决方案就是滚动您自己的函数
f
,该函数按您所希望的方式工作

import numpy as np
def f(x):
    return x * np.array([1,1,1,1,1], dtype=np.float32)
g = np.vectorize(f, otypes=[np.ndarray])
a = np.arange(4)
b = g(a)
b = np.array(b.tolist())
print(b)#b.shape = (4,5)
c = np.ones((2,3,4))
d = g(c)
d = np.array(d.tolist())
print(d)#d.shape = (2,3,4,5)

这应该可以解决问题,并且无论您的输入大小如何,它都可以工作。“地图”仅适用于一维输入。使用“.tolist()”并创建一个新的ndarray可以更完整、更好地解决这个问题(我相信)。希望这有帮助。

解决这一问题的最佳方法是使用二维NumPy数组(在本例中为列数组)作为原始函数的输入,然后该函数将生成一个二维输出,其结果我相信是您所期望的

下面是它在代码中的外观:

import numpy as np
def f(x):
    return x*np.array([1, 1, 1, 1, 1], dtype=np.float32)

a = np.arange(4).reshape((4, 1))
b = f(a)
# b is a 2-D array with shape (4, 5)
print(b)

这是一种更简单、更不容易出错的完成操作的方法。这种方法不是试图用numpy.vectorize转换函数,而是依赖于numpy广播数组的自然能力。诀窍是确保数组之间至少有一个维度的长度相等。

我已经编写了一个函数,它似乎适合您的需要

def amap(func, *args):
    '''array version of build-in map
    amap(function, sequence[, sequence, ...]) -> array
    Examples
    --------
    >>> amap(lambda x: x**2, 1)
    array(1)
    >>> amap(lambda x: x**2, [1, 2])
    array([1, 4])
    >>> amap(lambda x,y: y**2 + x**2, 1, [1, 2])
    array([2, 5])
    >>> amap(lambda x: (x, x), 1)
    array([1, 1])
    >>> amap(lambda x,y: [x**2, y**2], [1,2], [3,4])
    array([[1, 9], [4, 16]])
    '''
    args = np.broadcast(None, *args)
    res = np.array([func(*arg[1:]) for arg in args])
    shape = args.shape + res.shape[1:]
    return res.reshape(shape)
让我们试试

def f(x):
        return x * np.array([1,1,1,1,1], dtype=np.float32)
amap(f, np.arange(4))
输出

array([[ 0.,  0.,  0.,  0.,  0.],
       [ 1.,  1.,  1.,  1.,  1.],
       [ 2.,  2.,  2.,  2.,  2.],
       [ 3.,  3.,  3.,  3.,  3.]], dtype=float32)
为方便起见,您也可以用lambda或partial包装

g = lambda x:amap(f, x)
g(np.arange(4))

注意
vectorize
的docstring表示

矢量化
功能主要是为了方便,而不是为了 演出该实现本质上是一个for循环

因此,我们希望这里的
amap
具有与
vectorize
类似的性能。我没有检查,欢迎进行任何性能测试


如果性能是非常重要的,则应该考虑其他事项,例如用“代码”>“直接数组计算”/<代码>和<代码>广播< /代码>来避免纯Python中的循环(两者都是<代码>矢量化< /代码>和<代码> AMAP < /代码>是后面的情况)。

< P>> 1.12.0中的新参数<代码>签名< /代码>正是你所做的。

def f(x):
    return x * np.array([1,1,1,1,1], dtype=np.float32)

g = np.vectorize(f, signature='()->(n)')
然后
g(np.arange(4))。shape
将给出
(4L,5L)


此处指定了
f
的签名。
(n)
是返回值的形状,
()
是标量参数的形状。参数也可以是数组。有关更复杂的签名,请参阅。

要对函数进行矢量化

import numpy as np
def f(x):
    return x * np.array([1,1,1,1,1], dtype=np.float32)
假设您希望获得单个
np.float32
数组作为结果,则必须将其指定为
otype
。然而,您在问题中指定了
otypes=[np.ndarray]
,这意味着您希望每个元素都是
np.ndarray
。因此,您可以正确地得到
dtype=object
的结果

正确的电话是

np.vectorize(f, signature='()->(n)', otypes=[np.float32])
然而,对于这样一个简单的函数,最好利用
numpy
的uffunctions<代码>np.矢量化只需在其上循环即可。因此,在您的情况下,只需将函数重写为

def f(x):
    return np.multiply.outer(x, np.array([1,1,1,1,1], dtype=np.float32))

这会更快,产生更少的模糊错误(但是请注意,如果传递复数或四精度数字,结果将取决于
x

事实上,“只是一个方便的函数”描述了大部分numpy API。这就是重点。遗憾的是,此函数的行为与预期不符。大多数NumPy函数只比用C编写的等效函数慢一点。当NumPy函数只是C(或Fortran)函数的薄型包装器时,这一点是正确的。相反,向量化的
np.vectoriad
函数仍然必须为数组中的每个元素调用一次Python函数,因此它的性能更像Python代码而不是C代码。Python的动态名称查找提供了更大的灵活性,但可能比C代码慢得多。不是因为它不能像您预期的那样工作,而是因为您传递了
otypes=[np.ndarray]
。因此,您的结果是一个包含数组元素的数组,因此您可以得到
dtype=object
。你特别要求的。