web-dev-qa-db-ja.com

python)で1,000,000以上の乱数を生成する最速の方法

私は現在、大量の乱数を生成する必要があるpython、FASTでアプリを作成しています。現在、numpyを使用して巨大なバッチですべての数値を生成するスキームがあります(約一度に最大500,000)これはPythonの実装よりも高速のようですが、それでも高速化する必要があります。何かアイデアはありますか?Cで記述してプログラムに埋め込むか、必要な処理を実行します。 。

乱数の制約:

  • すべて異なる境界を持つことができる7つの数値のセット:
    • 例:[0-X1、0-X2、0-X3、0-X4、0-X5、0-X6、0-X7]
    • 現在、[0-1)からランダムな値で7つの数値のリストを生成し、[X1..X7]を掛けています。
  • 合計で1 になる13個の数字のセット
    • 現在、13の数値を生成し、それらの合計で除算しています

何か案は?これらの数値を事前に計算してファイルに保存すると、これが高速になりますか?

ありがとう!

24
Sandro

最初に説明したことを実行するだけで、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を大幅に打ち負かすことができるかどうかはわかりません...しかし、私は非常に間違っている可能性があります。

13
Joe Kington

[〜#〜] edit [〜#〜]一度に1行だけでなく、数値の完全なセットを返す関数を作成しました。 EDIT 2関数をよりPythonic(そしてより高速)にし、2番目の質問の解決策を追加します

最初の数値セットについては、numpy.random.randintまたはnumpy.random.uniformを検討してください。これらは、lowおよびhighパラメーターを取ります。指定された範囲で7x 1,000,000の数値の配列を生成するには、2GHzのマシンで0.7秒未満かかるようです。

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)の浮動小数点数を返します。私の2GHzシングルコアマシンでは、整数バージョンは約0.3秒、2倍は約0.66秒かかりました。

2番目のセットでは、@ JoeKingstonの提案を使用しました。

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番目のデータセットを提供します。

6
mtrw

r = 1664525*r + 1013904223をお試しください
「NumericalRecipesin C」第2版、Press et al。、isbn 0521431085、p。 284。
np.randomは確かに「よりランダム」です。 線形合同法 を参照してください。

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
'

一度に大きなブロックを生成するには:

# initialize --
np.random.seed( ... )
R = np.random.randint( 0, np.iinfo( np.uint32 ).max, size,  dtype=np.uint32 )
...
R *= 1664525
R += 1013904223
4
denis

他の人がすでに指摘しているように、numpyは非常に良いスタートであり、速くて使いやすいです。

大規模な乱数が必要な場合は、eas-ecbまたはrc4を検討してください。両方を並列化できます。数GB /秒でパフォーマンスに到達するはずです。

ここに掲載されている達成可能な数値

1
Dima Tisnek

コードを並行して実行することは確かに害にはなりません。 Parallel Python を使用してSMPに適合させてみてください

1
Jon W