2016-12-01 50 views
3

在我的代碼中,功能f(a,b)map()需要兩個1x3 numpy數組作爲輸入。由於它是從C代碼執行的其他人,因此我無法更改f()。第二個輸入y始終是Nx3 numpy數組。第一個輸入x有兩種情況。蟒蛇結合兩個邏輯的地圖()

在一種情況下,它是一個1×3 numpy的陣列,因此,我做

unwrap = partial(f, x) 
result = map(unwrap, y) 

在其他情況下,它是一個NX3 numpy的陣列,然後我做

unwrap = f 
result = map(unwrap, x, y) 

是否有一個將兩種情況結合在一起的方法?

回答

1

在第二種情況下,您將xy壓縮在一起並將其傳遞到f。在第一種情況下,您將f應用於x並將其映射到y--換句話說,您將f應用於常量參數和可變參數。

所以你應該能夠看到,將f應用於一個常量參數與將其映射到一個常量列表相同。特別是,

map(partial(f, x), y) == map(f, [x]*len(y), y) 

除了:Haskellers就知道這是的可適用的法律之一:

pure (f x) = fmap f (pure x) 

雖然他們的行爲一樣,他們沒有很相同的特點。我希望第二個分配更多的內存,並花費更長的時間運行。但這正是微觀優化的領域;除非你已經對它進行了簡介並確定你確實需要這些代碼儘可能快地達到人類可能的程度,否則最好選擇更乾淨的選項。

0

np.broadcast_to可'重塑'A匹配B;那麼你可以一起迭代兩者。它使用striding,所以沒有實際增加內存使用。

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]]) 

我通常使用列表解析而不是圖:

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陣列產生一維數組的列表,因此需要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處理這種廣播的爲好,但它們被設計爲帶標量,而不是一維數組功能。

隨着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)陣列。我可以通過生產(N,1,3)陣列擺脫atleast_2d的使用:

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]])]