只是在unubtu偉大的答案頂部的幾個性能指針。
np.einsum
無法優化具有兩個以上參數的調用。只要有可能,它通常更快的計算手動分成的兩個參數組是,例如:
def unubtu():
xbar = x-mu[:,None,:] # shape (3, 150, 4)
sigma = np.einsum('nk,knm,kno->kmo', gamma, xbar, xbar)
sigma /= gamma.sum(axis=0)[:,None,None]
return sigma
def faster():
xbar = x-mu[:,None,:] # shape (3, 150, 4)
sigma = np.einsum('knm,kno->kmo', gamma.T[..., None] * xbar, xbar)
sigma /= gamma.sum(axis=0)[:,None,None]
return sigma
In [50]: %timeit unubtu()
10000 loops, best of 3: 147 µs per loop
In [51]: %timeit faster()
10000 loops, best of 3: 129 µs per loop
提高了12%並不多,但差異可以得到(多少)有更大的陣列大。
此外,即使np.einsum
是一個很好的工具,它使得很容易的事情變得非常困難,但它並不像np.dot
那樣優化,如果你的numpy是用一個好的線性代數庫構建的話。在你的情況,考慮到K
小,使用np.dot
和Python的循環是更快:
def even_faster():
sigma = np.empty((K, M, M))
for k in xrange(K):
x_ = x - mu[k]
sigma[k] = np.dot((x_ * gamma[:, k, None]).T, x_)
sigma /= gamma.sum(axis=0)[:,None,None]
return sigma
In [52]: %timeit even_faster()
10000 loops, best of 3: 101 µs per loop
這僅僅是驚人的。謝謝你教我新東西! – VeilEclipse