在我的代码中,f(a,b)
的函数map()
需要两个1x3 numpy数组作为输入。由于它是C代码中其他人的实现,因此我无法更改f()
。
第二个输入y
始终是Nx3 numpy数组。第一个输入x
有两种情况。
在一种情况下,它是1x3 numpy数组,因此我
unwrap = partial(f, x)
result = map(unwrap, y)
在另一种情况下,它是一个Nx3 numpy数组,然后我
unwrap = f
result = map(unwrap, x, y)
有没有办法将两个案例合并在一起?
答案 0 :(得分:1)
在第二种情况下,您将x
和y
压缩在一起并将其传递给f
。在第一种情况下,您将f
应用于x
并将其映射到y
- 换句话说,您将f
应用于常量参数和变量1
因此,您应该能够看到将f
应用于常量参数与将其映射到常量列表相同。特别是,
map(partial(f, x), y) == map(f, [x]*len(y), y)
除了:Haskellers会将此视为适用法律之一:
pure (f x) = fmap f (pure x)
虽然它们的行为相同,但它们的特征并不完全相同。我希望第二个分配更多内存并运行更长时间。但这完全属于微观优化领域;除非你已经对它进行了分析并确定你真的需要这个代码尽可能快,否则最好选择更干净的选项。
答案 1 :(得分:1)
np.broadcast_to
可以'重塑'A
以匹配B
;然后你可以一起迭代这两个。它使用跨步,所以内存使用没有实际增加。
In [370]: def f(a,b):
...: assert(a.shape==(1,3))
...: assert(b.shape==(1,3))
...: return a+b
...:
In [371]: B=np.arange(12).reshape(4,3)
In [372]: A=np.arange(3).reshape(1,3)
In [373]: np.broadcast_to(A, B.shape) # (1,3) to (4,3)
Out[373]:
array([[0, 1, 2],
[0, 1, 2],
[0, 1, 2],
[0, 1, 2]])
In [374]: np.broadcast_to(B, B.shape) # no change with (4,3)
Out[374]:
array([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[ 9, 10, 11]])
我通常使用列表推导而不是map:
In [375]: [f(np.atleast_2d(a),np.atleast_2d(b)) for a,b in zip(np.broadcast_to(A,B.shape),B)]
Out[375]:
[array([[0, 2, 4]]),
array([[3, 5, 7]]),
array([[ 6, 8, 10]]),
array([[ 9, 11, 13]])]
In [376]: [f(np.atleast_2d(a),np.atleast_2d(b)) for a,b in zip(np.broadcast_to(B,B.shape),B)]
Out[376]:
[array([[0, 2, 4]]),
array([[ 6, 8, 10]]),
array([[12, 14, 16]]),
array([[18, 20, 22]])]
对2d数组的迭代产生1d数组的列表,因此需要np.atleast_2d
来满足我的f
断言。如果f
接受(3,)输入,我也不需要。
或map
:
In [377]: map(lambda a,b: f(np.atleast_2d(a),np.atleast_2d(b)), np.broadcast_to(B,B.shape),B)
Out[377]: <map at 0xb14f4c6c>
In [378]: list(_)
Out[378]:
[array([[0, 2, 4]]),
array([[ 6, 8, 10]]),
array([[12, 14, 16]]),
array([[18, 20, 22]])]
In [379]: map(lambda a,b: f(np.atleast_2d(a),np.atleast_2d(b)), np.broadcast_to(A,B.shape),B)
Out[379]: <map at 0xb0871a8c>
In [380]: list(_)
Out[380]:
[array([[0, 2, 4]]),
array([[3, 5, 7]]),
array([[ 6, 8, 10]]),
array([[ 9, 11, 13]])]
np.vectorize
和np.frompyfunc
也可以处理这种广播,但它们是针对采用标量而非1d数组的函数设计的。
使用broadcast_arrays
我可以平等对待两个数组:
In [386]: map(lambda a,b: f(np.atleast_2d(a),np.atleast_2d(b)), *np.broadcast_arrays(B,A))
Out[386]: <map at 0xb69851ac>
In [387]: list(_)
Out[387]:
[array([[0, 2, 4]]),
array([[3, 5, 7]]),
array([[ 6, 8, 10]]),
array([[ 9, 11, 13]])]
更一般地说,A
和B
可以是生成所需(N,3)
数组的任何内容。我可以通过生成atleast_2d
数组来消除(N,1,3)
使用:
In [397]: map(f, *np.broadcast_arrays(np.arange(3)[None,None,:], np.arange(0,40,10)[:,None,None]))
Out[397]: <map at 0xb08b562c>
In [398]: list(_)
Out[398]:
[array([[0, 1, 2]]),
array([[10, 11, 12]]),
array([[20, 21, 22]]),
array([[30, 31, 32]])]