2015-11-24 24 views
2

在Monte-Carlo模擬中,我以[[x0,y0,x1,y1]*N]的形式創建了許多隨機棍子座標列表(實際上每個重複代表兩種不同類型的棍子的兩個座標列表)。通過使用矢量化的numpy方法,我儘量減少了創建時間。但是,對於某些條件,陣列的長度超過10mio,並且發電成爲瓶頸。使用numpy創建許多隨機棍子座標的時間效率方式

下面的代碼給出最小例如用一些測試值

import numpy as np 

def create_coordinates_vect(dimensions=[1500,2500], length=50, count=12000000, type1_content=0.001): 
    # two arrays with random start coordinates in area of dimensions 
    x0 = np.random.randint(dimensions[0], size=count) 
    y0 = np.random.randint(dimensions[1], size=count) 
    # random direction of each stick 
    dirrad = 2 * np.pi * np.random.rand(count) 
    # to destinguish between type1 and type2 sticks based on random values 
    stick_type = np.random.rand(count) 
    is_type1 = np.zeros_like(stick_type) 
    is_type1[stick_type < type1_content] = True 
    # calculate end coordinates 
    x1 = x0 + np.rint(np.cos(dirrad) * length).astype(np.int32) 
    y1 = y0 + np.rint(np.sin(dirrad) * length).astype(np.int32) 
    # stack together start and end coordinates 
    coordinates = np.vstack((x0, y0, x1, y1)).T.astype(np.int32) 
    # split array according to type 
    coords_type1 = coordinates[is_type1 == True] 
    coords_type2 = coordinates[is_type1 == False] 
    return ([coords_type1, coords_type2]) 

list1, list2 = create_coordinates_vect() 

時序分析給出下面的結果爲不同的部分

=> x0, y0:      477.3640632629945 ms 
=> dirrad, stick_type:   317.4648284911094 ms 
=> is_type1:      27.3699760437172 ms 
=> x1, y1:      1184.7038269042969 ms 
=> vstack:      189.0783309965234 ms 
=> coords_type1, coords_type2: 309.9758625035176 ms 

我仍然可以通過定義數目獲得一些時間類型1和類型2事先粘在一起,而不是對每個棒進行隨機數比較。然而,創建隨機起始座標和方向以及結束座標計算的較長部分將保持不變。

有人看到進一步的優化,以加快數組的創建?

回答

2

由於時間表示x1 & y1計算是代碼中最慢的部分。其中,我們有cosinesine計算,與length縮放,然後舍入並轉換爲int32。現在,人們用來提高NumPy性能的方法之一是使用numexpr模塊。

在我們最慢的部分中,可以用numexpr計算的操作是sinecosine和縮放比例。因此,該代碼的numexpr修改後的版本是這樣的 -

import numexpr as ne 

x1 = x0 + np.rint(ne.evaluate("cos(dirrad) * length")).astype(np.int32) 
y1 = y0 + np.rint(ne.evaluate("sin(dirrad) * length")).astype(np.int32) 

運行測試 -

讓我們考慮(1/100)個形狀到原來的形狀排列。因此,我們有 -

dimensions=[15,25] 
length=50 
count=120000 
type1_content=0.001 

代碼的初始部分保持不變 -

# two arrays with random start coordinates in area of dimensions 
x0 = np.random.randint(dimensions[0], size=count) 
y0 = np.random.randint(dimensions[1], size=count) 

# random direction of each stick 
dirrad = 2 * np.pi * np.random.rand(count) 
# to destinguish between type1 and type2 sticks based on random values 
stick_type = np.random.rand(count) 
is_type1 = np.zeros_like(stick_type) 
is_type1[stick_type < type1_content] = True 

接下來,我們有兩個brances用於運行測試的目的 - 一個與原代碼和其他與提出numexpr基礎的方法 -

def org_app(x0,y0,dirrad,length): 
    x1 = x0 + np.rint(np.cos(dirrad) * length).astype(np.int32) 
    y1 = y0 + np.rint(np.sin(dirrad) * length).astype(np.int32) 

def new_app(x0,y0,dirrad,length): 
    x1 = x0 + np.rint(ne.evaluate("cos(dirrad) * length")).astype(np.int32) 
    y1 = y0 + np.rint(ne.evaluate("sin(dirrad) * length")).astype(np.int32) 

最後,運行測試本身 -

In [149]: %timeit org_app(x0,y0,dirrad,length) 
10 loops, best of 3: 23.5 ms per loop 

In [150]: %timeit new_app(x0,y0,dirrad,length) 
100 loops, best of 3: 14.6 ms per loop  

所以,我們正在尋找約40%在運行時減少,還不錯我猜!

+0

謝謝。我以前不知道'numexpr'。事實上,這加速了'x1'和'y1'的創建,並且它已經安裝在Windows和Ubuntu的Anaconda上。 – MrCyclophil