我想创建一个具有input:x.shape==(2,2)
和输出y.shape==(2,2,3)
的函数。
例如:
@np.vectorize
def foo(x):
#This function doesn't work like I want
return x,x,x
a = np.array([[1,2],[3,4]])
print(foo(a))
#desired output
[[[1 1 1]
[2 2 2]]
[[3 3 3]
[4 4 4]]]
#actual output
(array([[1, 2],
[3, 4]]), array([[1, 2],
[3, 4]]), array([[1, 2],
[3, 4]]))
或者也许:
@np.vectorize
def bar(x):
#This function doesn't work like I want
return np.array([x,2*x,5])
a = np.array([[1,2],[3,4]])
print(bar(a))
#desired output
[[[1 2 5]
[2 4 5]]
[[3 6 5]
[4 8 5]]]
请注意,foo
只是一个示例。 我想要一种方法来map
numpy 数组(这是矢量化应该做的),但map
拿一个 0d 对象并将一个 1d 对象推到它的位置。 在我看来,这里的维度是任意的,因为人们可能希望采用一个函数,该函数采用一个 1d 对象并返回一个 3d 对象,对其进行矢量化,在 5d 对象上调用它,然后返回一个 7d 对象......但是,我的具体用例只需要将 0d 矢量化到 1d 函数,并将其适当地映射到 2d 数组。
在您的问题中,显示实际结果和您想要的结果会有所帮助。 正如所写,这不是很清楚。
In [79]: foo(np.array([[1,2],[3,4]]))
Out[79]:
(array([[1, 2],
[3, 4]]), array([[1, 2],
[3, 4]]), array([[1, 2],
[3, 4]]))
如vectorize
文档中所述,这返回了一个数组元组,对应于函数返回的值元组。
您的bar
返回一个数组,其中vectorize
预期返回标量(或单个值):
In [82]: bar(np.array([[1,2],[3,4]]))
ValueError: setting an array element with a sequence.
vectorize
采用有时有帮助的otypes
参数。 例如,如果我说bar
(没有包装器)返回一个对象,我会得到:
In [84]: f=np.vectorize(bar, otypes=[object])
In [85]: f(np.array([[1,2],[3,4]]))
Out[85]:
array([[array([1, 2, 5]), array([2, 4, 5])],
[array([3, 6, 5]), array([4, 8, 5])]], dtype=object)
(3,) 个数组的 (2,2) 个数组。(2,2)
形状与输入的形状匹配。
vectorize
有一个相对较新的参数,signature
In [90]: f=np.vectorize(bar, signature='()->(n)')
In [91]: f(np.array([[1,2],[3,4]]))
Out[91]:
array([[[1, 2, 5],
[2, 4, 5]],
[[3, 6, 5],
[4, 8, 5]]])
In [92]: _.shape
Out[92]: (2, 2, 3)
我没有用过这么多,所以我仍然对它的工作原理有所了解。 当我测试它时,它比vectorize
的原始标量版本慢。 两者都不提供显式循环的任何速度优势。 但是,vectorize
在"广播"时确实有帮助,允许您使用各种输入形状。 当您的函数接受多个输入(而不是像本例中那样只有一个输入)时,这更有用。
In [94]: f(np.array([1,2]))
Out[94]:
array([[1, 2, 5],
[2, 4, 5]])
In [95]: f(np.array(3))
Out[95]: array([3, 6, 5])
为了获得最佳速度,您希望尽可能使用现有的 numpy 全数组函数。 例如,您的foo
案例可以通过以下方式完成:
In [97]: np.repeat(a[:,:,None],3, axis=2)
Out[97]:
array([[[1, 1, 1],
[2, 2, 2]],
[[3, 3, 3],
[4, 4, 4]]])
np.stack([a]*3, axis=2)
也有效。
以及您bar
期望的结果:
In [100]: np.stack([a, 2*a, np.full(a.shape, 5)], axis=2)
Out[100]:
array([[[1, 2, 5],
[2, 4, 5]],
[[3, 6, 5],
[4, 8, 5]]])
2*a
利用了全数组乘法。 这才是真正的"麻木"思维。
只需将值重复到另一个维度就非常简单:
import numpy as np
x = a = np.array([[1,2],[3,4]])
y = np.repeat(x[:,:,np.newaxis], 3, axis=2)
print y.shape
print y
(2L, 2L, 3L)
[[[1 1 1]
[2 2 2]]
[[3 3 3]
[4 4 4]]]
这似乎适用于"f R0 -> R1 映射到一个 nd 数组上,给出一个 (n+1)d">
def foo(x):
return np.concatenate((x,x))
np.apply_along_axis(foo,2,x.reshape(list(x.shape)+[1]))
不过,并不能很好地概括所有内容