向量化代碼

在MATLAB和數值計算的世界,for循環被剪掉,而向量為王。

我最喜歡的向量化例子是,一位同事在寫了一篇非常酷的論文,對其中所涉及的大量計算做了腳註,與我分享了他的lorenz96代碼。其中,內部的向量化速度比沒有向量化快了4倍。

現在,快速向量代碼使機器學習成為可能。例如QR分解,雖然我還沒做過,但我確信現在我可以用MATLAB或Numpy或Julia編寫。

我在MassMutual做的很多工作基本上都是數值計算,一條耗時數小時與耗時數秒的管道之間的差異巨大。秒意味著我們可以迭代,嘗試更多的選項。不過,為了靈活性,很多數值代碼都是用純Python(沒有Cython,沒有Numba)編寫的。我要說這是個壞想法!下面是一封同事的轉述郵件:

在偽代碼中,這是幾個月前我遇到的“精算”編碼難題:

EOM = 0 for months in years: PREM = 50 BOM = EOM + PREM WIT = 5 EOM = BOM – WIT

一個簡單的例子,但是我認為顯示了BOM/EOM的相互依賴性(還有一些其他變量具有相似的關係)。你不能在不知道EOM的情況下對BOM進行向量化,而且在知道BOM之前也不能對EOM進行向量化。如果WIT>0,PREM=0。基本上會出現很多相互依賴的情況。現在很多函數都不容易出現向量化。

好吧,我可以向量化這個,我做到了。以下是Python中的非向量化版本:

<code>

import

numpy as np

years

=

10

bom

=

np.zeros(years*12)

eom

=

np.zeros(years*12)

for

month in range(1, years*12):

prem

=

50

=

eom[month-1] + prem

wit

=

5

=

bom[month] - wit

/<code>

這是向量化版本:

<code>

import

numpy as np

years

=

10

prem

=

50

wit

=

5

eom

=

np.arange(years*12)*prem - np.arange(years*12)*wit

bom

=

eom + np.arange(years*12)*wit

/<code>

我還通過使用一系列字典來編寫for循環:

<code>years = 

10

prem =

50

wit =

5

result = [{

'bom'

:

0

,

'eom'

:

0

}]

for

month

in

range(

1

, years*

12

):

inner

= {}

inner

.update({

'bom'

: result[month-

1

][

'eom'

] + prem})

inner

.update({

'eom'

:

inner

[

'bom'

] - wit}) result.append(

inner

) /<code>

上面的這個返回一個不同類型的東西,一個dict列表…而不是兩個數組。

我們還可以導入Pandas來填充上述三個結果的結果(因此它們是一致的輸出,我們可以保存到excel中,等等)。如果加載了Pandas,則可以使用空數據幀進行迭代,因此還有一個選項:

<code>

import

numpy

as

np

import

pandas

as

pd years =

10

prem =

50

wit =

5

df = pd.DataFrame(

data

={

'bom'

: np.zeros(years*

12

),

'eom'

: np.zeros(years*

12

)})

for

i, row

in

df.iterrows():

if

i >

0

: row.bom = df.loc[i-

1

,

'eom'

] row.eom = row.bom - wit /<code>

對於所有這些類型的迭代,以及返回數據幀作為結果的選項,我們得到的結果是:

向量化代碼

Cython 和Numba

我還添加了一些Cython版本的代碼,說明使用C可以在不使用numpy的情況下獲得向量化的性能,這確實可能在可讀性還有速度之間達到最佳平衡(保持for循環!)。

Numba也可以加速(它可能和Cython/Vectorized Numpy一樣快)。在這兩種情況下(Cython/Numba),你必須小心使用哪些數據類型(因為沒有dicts或pandas!)。我認為,如果你對如何集成Cython+Numpy循環更聰明的話,它將有可能使Cython+Numpy循環與向量化Numpy一樣快。

所有代碼,包括Cython,都可以在這裡找到:
https://github.com/andyreagan/vectorizing-matters。


分享到:


相關文章: