2011-03-11 58 views
1

我有一個模擬我的博士論文以下挑戰:高效的數學運算

我需要優化下面的代碼:

repelling_forces = repelling_force_prefactor * np.exp(-(height_r_t/potential_steepness)) 

在此代碼段'height_r_t'是一個真正的Numpy數組,'potential_steepness'是一個標量。 'repelling_force_prefactor'也是一個Numpy數組,它大部分爲零,但是在預先計算的位置爲1,在運行時不會改變(即Mask)。 很明顯,代碼是低效的,因爲只有在'repelling_force_prefactor'非零的位置計算指數函數才更有意義。

問題是我該如何以最有效的方式做到這一點?

我到現在爲止的唯一想法是使用'repelling_force_prefactor'將切片定義爲'height_r_t',並將'np.exp'應用於這些切片。但是,我已經做出了切片慢的經驗(不知道這是否正確),而且解決方案看起來很尷尬。

正如一個側面說明'repelling_force_prefactor'中1到0的比例大約是1/1000,我在循環中運行它,所以效率非常重要。 (評論:我不會遇到使用Cython的問題,因爲無論如何我都需要/想要學習它......但是我是新手,所以我需要一個好的指針/解釋。)

回答

3

蒙面陣列正是爲您的目的而實施的。

性能是一樣的斯文的回答是:

height_r_t = np.ma.masked_where(repelling_force_prefactor == 0, height_r_t) 
repelling_forces = np.ma.exp(-(height_r_t/potential_steepness)) 

蒙面陣列的好處是,你不必切片和擴展陣列,大小始終是相同的,但numpy的自動知道不計算數組被屏蔽的exp。

另外,您可以用不同的掩碼對數組進行求和,得到的數組具有掩碼的交集。

+0

這是一個非常整潔,因爲優雅的解決方案。另一個問題 - 也許你在最後一句中提到了這個問題。我可以使用這種方法在矩陣的不同部分進行操作嗎?即像這樣: height_part1 =身高(掩碼1) height_part2 =身高(掩碼2) – packoman 2011-03-12 19:34:53

+0

然後,然後如果我在height_part1或height_part2,像height_part1 = operation1(height_part1),做數學運算,將這些被高度體現? – packoman 2011-03-12 19:42:18

+0

是的,該掩碼是存儲在masked_array的'.mask'屬性中的簡單布爾數組。當你創建一個被屏蔽的數組時,你可以指定copy = False,以便你的操作被反映到原始數組中。但最好的策略取決於你的應用程序的細節。 – 2011-03-14 02:59:32

2

切片可能比計算所有指數要快得多。除了使用面膜repelling_force_prefactor直接切片的,我建議預先計算的指數它是非零,並將其用於切片:

# before the loop 
indices = np.nonzero(repelling_force_prefactor) 

# inside the loop 
repelling_forces = np.exp(-(height_r_t[indices]/potential_steepness)) 

現在repelling_forces將只包含非零的結果。如果必須用此值更新height_r_t的原始形狀的某個數組,則可以再次使用indices進行切片,或使用np.put()或類似的函數。

在這種情況下,使用索引列表切片將比使用布爾掩碼切片效率更高,因爲索引列表的長度縮短了千分之一。實際上衡量表現當然取決於你。

+0

+1擊敗我。我只會補充說,有幾個選擇可以做到這一點,最好的做法是如果你的代碼的這一部分是瓶頸,就要對每個選項進行基準測試。一般來說,我發現切片速度非常快,特別是如果比例是1/1000。 – JoshAdel 2011-03-11 17:30:51