numpy:如何向量化返回不同形状数组的函数?
numpy: How to vectorize a function returning arrays of different shapes?
我需要矢量化一个函数,该函数可以 return 形状为 (2,3)
或 (3,3)
的数组。可能吗?
我这样创建矢量化函数:
my_func_v = np.vectorize(my_func, signature='()->(n,m)')
而且只要函数returns只有(2,3)或(3,3)数组,就可以正常工作。但是一旦结果形状混合,numpy 就会失败并出现错误:
ValueError: could not broadcast input array from shape (3,3) into
shape (2,3)
是否可以混合来自矢量化函数的 returned 形状?
我可能不应该花时间,因为您没有提供最小的工作示例。但是让我举例说明 signature
:
In [190]: f = np.vectorize(lambda x: x * np.ones((2, 3), int), signature="()->(n,m)")
In [191]: f(np.arange(4))
Out[191]:
array([[[0, 0, 0],
[0, 0, 0]],
[[1, 1, 1],
[1, 1, 1]],
[[2, 2, 2],
[2, 2, 2]],
[[3, 3, 3],
[3, 3, 3]]])
return 的形状是参数加上 (n,m)。显然对于数字数组,最后两个维度不能混合。上面产生 (4,2,3),下面产生 (2,2,2,3)
In [192]: f(np.arange(4).reshape(2,2))
Out[192]:
array([[[[0, 0, 0],
[0, 0, 0]],
[[1, 1, 1],
[1, 1, 1]]],
[[[2, 2, 2],
[2, 2, 2]],
[[3, 3, 3],
[3, 3, 3]]]])
如果我删除签名,并指定对象 return 类型:
In [194]: f = np.vectorize(lambda x: x * np.ones((2, 3), int), otypes=['object'])
In [195]: f(np.arange(4).reshape(2, 2))
Out[195]:
array([[array([[0, 0, 0],
[0, 0, 0]]), array([[1, 1, 1],
[1, 1, 1]])],
[array([[2, 2, 2],
[2, 2, 2]]), array([[3, 3, 3],
[3, 3, 3]])]], dtype=object)
现在元素数组的形状可以变化。
通常我不鼓励使用 vectorize
,因为它不是真正的“矢量化”。它有明确的性能免责声明。对象 dtype 数组比列表好一点,在某些方面更差。
In [196]: timeit f(np.arange(1000))
9.45 ms ± 67.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [197]: timeit [x*np.ones((2,3),int) for x in range(1000)]
9.46 ms ± 290 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [198]: timeit np.array([x*np.ones((2,3),int) for x in range(1000)])
9.83 ms ± 20.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
以前 np.vectorize
比等效的列表理解慢。现在它对于小参数仍然较慢,但它的扩展性更好。
我需要矢量化一个函数,该函数可以 return 形状为 (2,3)
或 (3,3)
的数组。可能吗?
我这样创建矢量化函数:
my_func_v = np.vectorize(my_func, signature='()->(n,m)')
而且只要函数returns只有(2,3)或(3,3)数组,就可以正常工作。但是一旦结果形状混合,numpy 就会失败并出现错误:
ValueError: could not broadcast input array from shape (3,3) into shape (2,3)
是否可以混合来自矢量化函数的 returned 形状?
我可能不应该花时间,因为您没有提供最小的工作示例。但是让我举例说明 signature
:
In [190]: f = np.vectorize(lambda x: x * np.ones((2, 3), int), signature="()->(n,m)")
In [191]: f(np.arange(4))
Out[191]:
array([[[0, 0, 0],
[0, 0, 0]],
[[1, 1, 1],
[1, 1, 1]],
[[2, 2, 2],
[2, 2, 2]],
[[3, 3, 3],
[3, 3, 3]]])
return 的形状是参数加上 (n,m)。显然对于数字数组,最后两个维度不能混合。上面产生 (4,2,3),下面产生 (2,2,2,3)
In [192]: f(np.arange(4).reshape(2,2))
Out[192]:
array([[[[0, 0, 0],
[0, 0, 0]],
[[1, 1, 1],
[1, 1, 1]]],
[[[2, 2, 2],
[2, 2, 2]],
[[3, 3, 3],
[3, 3, 3]]]])
如果我删除签名,并指定对象 return 类型:
In [194]: f = np.vectorize(lambda x: x * np.ones((2, 3), int), otypes=['object'])
In [195]: f(np.arange(4).reshape(2, 2))
Out[195]:
array([[array([[0, 0, 0],
[0, 0, 0]]), array([[1, 1, 1],
[1, 1, 1]])],
[array([[2, 2, 2],
[2, 2, 2]]), array([[3, 3, 3],
[3, 3, 3]])]], dtype=object)
现在元素数组的形状可以变化。
通常我不鼓励使用 vectorize
,因为它不是真正的“矢量化”。它有明确的性能免责声明。对象 dtype 数组比列表好一点,在某些方面更差。
In [196]: timeit f(np.arange(1000))
9.45 ms ± 67.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [197]: timeit [x*np.ones((2,3),int) for x in range(1000)]
9.46 ms ± 290 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [198]: timeit np.array([x*np.ones((2,3),int) for x in range(1000)])
9.83 ms ± 20.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
以前 np.vectorize
比等效的列表理解慢。现在它对于小参数仍然较慢,但它的扩展性更好。