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
。你特别要求的。