2014-11-08 87 views
0

我正在使用numpy.random.shuffle來計算二維數組隨機列的統計量。 Python的代碼如下:numpy.random.shuffle有更快的版本嗎?

import numpy as np 

def timeline_sample(series, num): 
    random = series.copy() 
    for i in range(num): 
     np.random.shuffle(random.T) 
     yield random 

我得到的速度是這樣的:

import numpy as np 
arr = np.random.sample((50, 5000)) 

%%timeit 
for series in timeline_sample(rnd, 100): 
    np.sum(series) 
 
1 loops, best of 3: 391 ms per loop 

我試圖Cythonize這個功能,但我不知道如何取代np.random.shuffle和func的呼叫重刑慢了3倍。有誰知道如何加速或取代這個?這是目前我的計劃中的瓶頸。

用Cython代碼:

cimport cython 

import numpy as np 
cimport numpy as np 


@cython.boundscheck(False) 
@cython.wraparound(False) 
def timeline_sample2(double[:, ::1] series, int num): 
    cdef double[:, ::1] random = series.copy() 
    cdef int i 
    for i in range(num): 
     np.random.shuffle(random.T) 
     yield random 
+0

我大概計算導致大約600 MB/s的吞吐量,考慮到您對數據進行多次通過,並且*每個timeline_sample調用產生大約3M個隨機整數,這並不算太壞。 OTOH你的數據集是70 KiB,它應該適合二級緩存,其中內存帶寬應該明顯更大。我不確定是否可以顯着提高性能。 – delnan 2014-11-08 15:12:12

+0

謝謝你的球場號碼。我的真實代碼寧可是一個尺寸爲40 x 5000的數組,是否會對您的估計產生顯着影響? – Midnighter 2014-11-08 15:29:51

回答

2

這可能是因爲這將提供一個很好的速度提升:

from timeit import Timer 

import numpy as np 
arr = np.random.sample((50, 5000)) 

def timeline_sample(series, num): 
    random = series.copy() 
    for i in range(num): 
     np.random.shuffle(random.T) 
     yield random 

def timeline_sample_fast(series, num): 
    random = series.T.copy() 
    for i in range(num): 
     np.random.shuffle(random) 
     yield random.T 

def timeline_sample_faster(series, num): 
    length = arr.shape[1] 
    for i in range(num): 
     yield series[:, np.random.permutation(length)] 

def consume(iterable): 
    for s in iterable: 
     np.sum(s) 

min(Timer(lambda: consume(timeline_sample(arr, 1))).repeat(10, 10)) 
min(Timer(lambda: consume(timeline_sample_fast(arr, 1))).repeat(10, 10)) 
min(Timer(lambda: consume(timeline_sample_faster(arr, 1))).repeat(10, 10)) 
#>>> 0.2585161680035526 
#>>> 0.2416607110062614 
#>>> 0.04835709399776533 

迫使它是連續並增加時間,而不是由一噸:

def consume(iterable): 
    for s in iterable: 
     np.sum(np.ascontiguousarray(s)) 

min(Timer(lambda: consume(timeline_sample(arr, 1))).repeat(10, 10)) 
min(Timer(lambda: consume(timeline_sample_fast(arr, 1))).repeat(10, 10)) 
min(Timer(lambda: consume(timeline_sample_faster(arr, 1))).repeat(10, 10)) 
#>>> 0.2632228760048747 
#>>> 0.25778737501241267 
#>>> 0.07451769898761995 
+0

我可以發誓,我試過這個(也許我正在排列行)。這確實更快,謝謝! – Midnighter 2014-11-08 15:43:39

1

隨機化行會更便宜,下面的代碼是在功能上等同,但速度更快 約3倍我的機器上。

def timeline_sample_fast(series, num): 
    random = series.T.copy() 
    for i in range(num): 
     np.random.shuffle(random) 
     yield random.T 



arr = np.random.sample((600, 50)) 

%%timeit       
for s in timeline_sample(arr, 100): 
    np.sum(s) 

10 loops, best of 3: 55.5 ms per loop 

%%timeit 
for s in timeline_sample_fast(arr, 100): 
    np.sum(s) 

10 loops, best of 3: 18.6 ms per loop 
+0

謝謝你的回覆。不幸的是,隨着數組維度更接近我的真實代碼,這不再是真實的。它仍然更快但不是太多。我編輯了我的問題以包含這些維度。我應該從一開始就這樣做。我道歉。 – Midnighter 2014-11-08 15:34:08

+0

我還需要使用隨機數組的C代碼的行是C連續的。因此,如果我不得不將'timeline_sample_fast'返回的值複製到一個相同形狀的C連續數組中,那麼我認爲,這個小的速度優勢會丟失。 – Midnighter 2014-11-08 15:41:18