python结合map()的两个逻辑

时间:2016-12-01 14:14:05

标签: python numpy dictionary

在我的代码中,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)

有没有办法将两个案例合并在一起?

2 个答案:

答案 0 :(得分:1)

在第二种情况下,您将xy压缩在一起并将其传递给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.vectorizenp.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]])]

更一般地说,AB可以是生成所需(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]])]