2016-09-19 68 views
4

希望儘快完成此計算。我有X作爲n x m numpy數組。我想定義y以如下所示:numpy數組的計算/操作

Y_11 = 1/(exp(X_11-X_11) + exp(X_11-X_12) + ... exp(X_11 - X_1N)).

或Y_00

1/np.sum(np.exp(X[0,0]-X[0,:]))

因此,基本上,Y是也n×m個,其中I,J的元素是1/sum_j」 exp(X_ij - X_ij')

任何提示都會很棒!謝謝。根據要求

示例代碼:

np.random.seed(111) 
J,K = 110,120 
X = np.random.rand(J,K) 
Y = np.zeros((J,K)) 
for j in range(J): 
    for k in range(K): 
     Y[j,k] = 1/np.sum(np.exp(X[j,k]-X[j,:])) 

# note each row will sum to 1 under this operation 
np.sum(Y,axis=1) 
+1

'exp'調用在第二個表達式中出現在哪裏? – user2357112

+0

感謝您發現我放棄了exp()。我還添加了一些代碼。 – Kevin

+0

這現在是一個很好的問題。在未來,如果你能像現在這樣寫東西,那將是非常好的。 –

回答

6

這裏有一些完全量化的辦法 -

def vectorized_app1(X): 
    return 1/np.exp(X[:,None] - X[...,None]).sum(1) 

def vectorized_app2(X): 
    exp_vals = np.exp(X) 
    return 1/(exp_vals[:,None]/exp_vals[...,None]).sum(1) 

def vectorized_app3(X): 
    exp_vals = np.exp(X) 
    return 1/np.einsum('ij,ik->ij',exp_vals,1/exp_vals) 

使用的技巧和經驗教訓

  • 使用None/np.newaxis擴展尺寸以引入廣播並以矢量化方式執行所有操作。

  • np.exp是一個昂貴的操作。因此,在廣播陣列上使用它會很昂貴。所以,使用的技巧是:exp(A-B) = exp(A)/exp(B)。因此,我們預先執行np.exp(X),然後執行廣播部門。

  • 可以用np.einsum來實現這些減少量。這帶來了內存效率,因爲我們不必創建巨大的廣播陣列,而且這種效果可以大幅提升性能。

運行測試 -

In [111]: # Setup input, X 
    ...: np.random.seed(111) 
    ...: J,K = 110,120 
    ...: X = np.random.rand(J,K) 
    ...: 

In [112]: %timeit original_approach(X) 
1 loop, best of 3: 322 ms per loop 

In [113]: %timeit vectorized_app1(X) 
10 loops, best of 3: 124 ms per loop 

In [114]: %timeit vectorized_app2(X) 
100 loops, best of 3: 14.6 ms per loop 

In [115]: %timeit vectorized_app3(X) 
100 loops, best of 3: 3.01 ms per loop 

貌似einsum100x+增速再次顯示出它的魔力!

+0

非常有用的答案。感謝所有的解釋。 –

+0

謝謝!然而有一個問題是有時A或B的值很大,所以我得到一個錯誤。我對使用exp(A-B)的想法是,我收縮了很多這些數據,並且可以放入np.min(A-B,200)或類似數據以避免錯誤。任何其他想法? – Kevin

+0

@Kevin究竟是什麼錯誤?它說什麼?在exp中出現 – Divakar

2

這裏的減少雙循環的第一步:

def foo2(X): 
    Y = np.zeros_like(X) 
    for k in range(X.shape[1]): 
     Y[:,k]=1/np.exp(X[:,[k]]-X[:,:]).sum(axis=1) 
    return Y 

我懷疑我還可以去除k循環,但我必須花有更多的時間弄清楚它在做什麼。那X[:,[k]]-X[:,:]並不明顯(在大圖中)。

另一個步驟:

Z = np.stack([X[:,[k]]-X for k in range(X.shape[1])],2) 
Y = 1/np.exp(Z).sum(axis=1) 

這可以進一步完善(太多的試驗和錯誤)與

Z = X[:,None,:]-X[:,:,None] 
+0

很好的回答。非常小的評論:在你最後的括號中,你是否意思是「*沒有太多的試驗和錯誤」。 –

+0

不,我嘗試了一些替代方案。有'X'可以擴展到3d的各種方式。和3軸可以相加。我沒有像以前那樣系統化。 – hpaulj