web-dev-qa-db-ja.com

numpyで大きなランダムブール行列を作成する

与えられた確率booleanTrueFalseでランダムに満たされる巨大なp行列を作成しようとしています。最初はこのコードを使用しました:

N = 30000
p = 0.1
np.random.choice(a=[False, True], size=(N, N), p=[p, 1-p])  

しかし、悲しいことに、この大きなNで終了しないようです。だから私はこれを行うことで単一行の生成に分割しようとしました:

N = 30000
p = 0.1
mask = np.empty((N, N))
for i in range (N):
     mask[i] = np.random.choice(a=[False, True], size=N, p=[p, 1-p])            
     if (i % 100 == 0):
          print(i)

今、奇妙なことが起こります(少なくとも私のデバイスでは):最初の〜1100行は非常に高速に生成されます-しかし、その後、コードはひどく遅くなります。なんでこんなことが起こっているの?ここで何が恋しいですか? Trueエントリの確率がpおよびFalseエントリの確率が1-pである大きな行列を作成するより良い方法はありますか?

編集:多くの人がRAMが問題になると仮定しました:コードを実行するデバイスはほぼ500GBのRAMを持っているため、これは問題。

18
FlashTek

問題はRAMであり、値は作成時にメモリに保存されます。このコマンドを使用してこのマトリックスを作成しました。

np.random.choice(a=[False, True], size=(N, N), p=[p, 1-p])

64GBのRAMおよび8コアのAWS i3インスタンスを使用しました。このマトリックスを作成するために、htopは20GBのRAMを占有することを示しています。気になる場合のベンチマーク:

time np.random.choice(a=[False, True], size=(N, N), p=[p, 1-p])

CPU times: user 18.3 s, sys: 3.4 s, total: 21.7 s
Wall time: 21.7 s


 def mask_method(N, p):
    for i in range(N):
        mask[i] = np.random.choice(a=[False, True], size=N, p=[p, 1-p])
        if (i % 100 == 0):
            print(i)

time mask_method(N,p)

CPU times: user 20.9 s, sys: 1.55 s, total: 22.5 s
Wall time: 22.5 s

マスクメソッドは、ピーク時にRAMの最大9GBしか使用しないことに注意してください。

編集:最初のメソッドは、関数メソッドがすべてを保持しているプロセスが完了した後、RAMをフラッシュします。

10
aws_apprentice

だから私はこれを行うことで単一行の生成に分割しようとしました:

np.random.choiceが機能する方法は、まずデータのすべてのセルに対してfloat64[0, 1)を生成し、それをnp.search_sortedを使用して配列のインデックスに変換することです。この中間表現は、ブール配列の8倍です!

データはブール値であるため、次のようにして2倍の速度を得ることができます。

np.random.Rand(N, N) > p

当然、ループソリューション内で使用できます

np.random.choiceはここでいくつかのバッファリングを行うことができるようです-numpyに対して問題を報告することができます。

別のオプションは、float32sの代わりにfloat64sを生成しようとすることです。 numpyが今すぐできるかどうかはわかりませんが、機能をリクエストできます。

4
Eric

別の可能性は、バッチで生成することです(つまり、多くのサブ配列を計算し、最後に一緒にスタックします)。ただし、OPが行っているように、maskループ内の1つの配列(for)を更新しないことを検討してください。これにより、インデックス更新のたびにアレイ全体がメインメモリに強制的にロードされます。

代わりに、たとえば:30000x30000、9000を持っています100x100個別の配列、このそれぞれを更新100x100に応じてforループに配列し、最終的にこれらの9000配列を巨大配列にスタックします。これは間違いなく4GB以下のRAMであり、非常に高速です。

最小限の例:

In [9]: a
Out[9]: 
array([[0, 1],
       [2, 3]])

In [10]: np.hstack([np.vstack([a]*5)]*5)
Out[10]: 
array([[0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
       [2, 3, 2, 3, 2, 3, 2, 3, 2, 3],
       [0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
       [2, 3, 2, 3, 2, 3, 2, 3, 2, 3],
       [0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
       [2, 3, 2, 3, 2, 3, 2, 3, 2, 3],
       [0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
       [2, 3, 2, 3, 2, 3, 2, 3, 2, 3],
       [0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
       [2, 3, 2, 3, 2, 3, 2, 3, 2, 3]])

In [11]: np.hstack([np.vstack([a]*5)]*5).shape
Out[11]: (10, 10)
0
kmario23