私は現在、大量の乱数を生成する必要があるpython、FASTでアプリを作成しています。現在、numpyを使用して巨大なバッチですべての数値を生成するスキームがあります(約一度に最大500,000)これはPythonの実装よりも高速のようですが、それでも高速化する必要があります。何かアイデアはありますか?Cで記述してプログラムに埋め込むか、必要な処理を実行します。 。
乱数の制約:
何か案は?これらの数値を事前に計算してファイルに保存すると、これが高速になりますか?
ありがとう!
最初に説明したことを実行するだけで、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を大幅に打ち負かすことができるかどうかはわかりません...しかし、私は非常に間違っている可能性があります。
[〜#〜] 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番目のデータセットを提供します。
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
他の人がすでに指摘しているように、numpy
は非常に良いスタートであり、速くて使いやすいです。
大規模な乱数が必要な場合は、eas-ecbまたはrc4を検討してください。両方を並列化できます。数GB /秒でパフォーマンスに到達するはずです。
コードを並行して実行することは確かに害にはなりません。 Parallel Python を使用してSMPに適合させてみてください