2010-04-25 216 views
21

我目前正在編寫一個應用程序,它需要生成大量的隨機數FAST。目前我有一個計劃使用numpy來生成大批量的所有數字(一次約500,000個)。雖然這似乎比python的實現更快。我仍然需要它走得更快。有任何想法嗎?我願意用C編寫它,並將它嵌入到程序中或者做它需要的東西。該隨機數字在Python中生成1,000,000個以上隨機數的最快方法

限制條件:

  • A設置7個數字的,可以全部具有不同的界限:
    • 例如:[0-X1,0-X2,0-X3,O- X4,O-X5,0-X6,0-X7]
    • 目前我從產生7號與隨機值的列表
  • [0-1)然後,通過[X1..X7乘以]一組13個數字,全部加起來爲1
    • 目前只產生13號然後通過它們的和

任何想法劃分?預先計算這些數字並將它們存儲在文件中會使速度更快?

謝謝!

+2

這幾乎是一個保證,去磁盤I/O不會讓它更快,所以文件存儲方法可能不是你想要的。 – 2010-04-25 20:25:55

+0

數字的範圍是什麼?我認爲他們是浮點? 你要走多快?你需要多少隨機性?你能通過生成N/7數字並旋轉它們嗎?m – Anycorn 2010-04-25 20:26:45

+0

這些數字在需要時隨機生成有多重要?這可能是一個選擇,可能存儲5倍以前生成的隨機數,並選擇一組隨機數? – poke 2010-04-25 20:28:05

回答

11

適應它SMP您可以只用做您最初描述的內容(生成一串隨機數和乘以相應劃分)加快東西從什麼mtrw上面貼了一下......

另外,您可能已經知道這一點,但在處理大型numpy數組時,一定要在原地進行操作(* =,/ =,+ =等)。它對大型陣列的內存使用量產生了巨大的影響,並且也會顯着提高速度。

In [53]: def rand_row_doubles(row_limits, num): 
    ....:  ncols = len(row_limits) 
    ....:  x = np.random.random((num, ncols)) 
    ....:  x *= row_limits     
    ....:  return x       
    ....:          
In [59]: %timeit rand_row_doubles(np.arange(7) + 1, 1000000) 
10 loops, best of 3: 187 ms per loop 

相比於:

In [66]: %timeit ManyRandDoubles(np.arange(7) + 1, 1000000) 
1 loops, best of 3: 222 ms per loop 

這不是一個巨大的差異,但如果你真的擔心速度,它的東西。

只是爲了表明它是正確的:

In [68]: x.max(0) 
Out[68]: 
array([ 0.99999991, 1.99999971, 2.99999737, 3.99999569, 4.99999836, 
     5.99999114, 6.99999738]) 

In [69]: x.min(0) 
Out[69]: 
array([ 4.02099599e-07, 4.41729377e-07, 4.33480302e-08, 
     7.43497138e-06, 1.28446819e-05, 4.27614385e-07, 
     1.34106753e-05]) 

同樣,你的「行總和爲1」的一部分......

In [70]: def rand_rows_sum_to_one(nrows, ncols): 
    ....:  x = np.random.random((ncols, nrows)) 
    ....:  y = x.sum(axis=0) 
    ....:  x /= y 
    ....:  return x.T 
    ....: 

In [71]: %timeit rand_rows_sum_to_one(1000000, 13) 
1 loops, best of 3: 455 ms per loop 

In [72]: x = rand_rows_sum_to_one(1000000, 13) 

In [73]: x.sum(axis=1) 
Out[73]: array([ 1., 1., 1., ..., 1., 1., 1.]) 

老實說,即使你重新實現用C事,我不確定你會在這一場比賽中大大地擊敗numpy ......不過我可能是錯的!

+0

@Joe - 我嘗試了有限數字的方法,發現它在我的機器上速度較慢。我很好奇,如果你可以嘗試我的比較?我也偷了你的方法爲總和爲1的數字;它比我之前嘗試的方式快得多。謝謝! – mtrw 2010-04-25 23:05:12

+0

@ mtrw-現在,您的更新函數比我的更快。 (166ms vs 184ms)你不需要整個內存塊都是連續的,只是每列的內存,我認爲這是造成差異的主要原因。缺點是在數據創建後訪問數據。你必須使用列表解析(或類似)爲你的,而我的返回一個單一的二維numpy陣列(稍快,更靈活的索引)。但是,如果您只需要一次訪問一行,則無關緊要。乾杯! – 2010-04-26 00:41:53

+0

感謝您的辛勤工作!試圖將代碼拼接在一起... – Sandro 2010-04-26 00:44:19

6

編輯創建的函數返回整組數字,而不是一次一行。 EDIT 2使功能更Python(快),對第二個問題

加解決方案的第一組數字,你可能會考慮numpy.random.randintnumpy.random.uniform,內搭lowhigh參數。在規定範圍內產生的7×1000000號數組似乎採取<0.7秒我的2GHz的機器上:

def LimitedRandInts(XLim, N): 
    rowlen = (1,N) 
    return [np.random.randint(low=0,high=lim,size=rowlen) for lim in XLim] 

def LimitedRandDoubles(XLim, N): 
    rowlen = (1,N) 
    return [np.random.uniform(low=0,high=lim,size=rowlen) for lim in XLim] 

>>> import numpy as np 
>>> N = 1000000 #number of randoms in each range 
>>> xLim = [x*500 for x in range(1,8)] #convenient limit generation 
>>> fLim = [x/7.0 for x in range(1,8)] 
>>> aa = LimitedRandInts(xLim, N) 
>>> ff = LimitedRandDoubles(fLim, N) 

這將返回整數在[0,XLIM-1]或漂浮[0,FLIM) 。在我的2 GHz單核機器上,整數版本花費了〜0.3秒,雙倍〜0.66。

對於第二套,我使用了@Joe金斯頓的建議。

def SumToOneRands(NumToSum, N): 
    aa = np.random.uniform(low=0,high=1.0,size=(NumToSum,N)) #13 rows by 1000000 columns, for instance 
    s = np.reciprocal(aa.sum(0)) 
    aa *= s 
    return aa.T #get back to column major order, so aa[k] is the kth set of 13 numbers 

>>> ll = SumToOneRands(13, N) 

這需要〜1.6秒。

在所有情況下,result[k]爲您提供第k組數據。

+0

如果你乘以倒數而不是浮點性能,你可能會贏得幾個週期。 – Anycorn 2010-04-25 20:40:32

+0

我必須給那一個重擊。你知道水平堆疊數組的性能嗎(不知道該怎麼說)來組合數組? – Sandro 2010-04-25 20:46:38

+0

@aaa - 謝謝,我將你的建議帶入了答案。 @Sandro - 我認爲堆疊不是很棒。您可能能夠預先分配數組。我會看看我能否做出這項工作並更新答案。 – mtrw 2010-04-25 20:52:18

1

讓你的代碼並行運行肯定不會受到傷害。試着用Parallel Python

+2

實際上,由於需要大容量內存,複製內存或通過管道發送內存非常昂貴,迄今實際上已經讓我放慢了速度。 – Sandro 2010-04-25 21:09:38

3

嘗試r = 1664525*r + 1013904223
從「一個更快的生成」 在「數字食譜在C」第二版,出版社等,ISBN 0521431085,第284.
np.random肯定是「更隨機」;見 Linear congruential generator

在Python中,使用np.uint32這樣的:

python -mtimeit -s ' 
import numpy as np 
r = 1 
r = np.array([r], np.uint32)[0] # 316 py -> 16 us np 
    # python longs can be arbitrarily long, so slow 
' ' 
r = r*1664525 + 1013904223 # NR2 p. 284 
' 
1

正如其他人已經指出,numpy是一個很好的開始,快速和易於使用。

如果您需要大規模的隨機數,請考慮eas-ecb或rc4。兩者可以並行,你應該達到幾GB/s的性能。

achievable numbers posted here

+0

我不認爲你的答案增加了新的信息? – nemo 2013-10-08 18:55:48

+0

添加了一個鏈接... – 2013-10-08 20:34:00

-1

在行動numpy只是一個簡單的例子:

data = numpy.random.rand(1000000) 

無需循環,你可以在你想要多少個號碼生成傳遞。

相關問題