所以我有一個大的 3D 陣列(~ 2000 x 1000 x 1000)。我想將陣列中的每個值更新為 1 和當前最大值之間的隨機整數值,以便所有值 = x 都更新為相同的隨機整數。我想保持零不變。也不能有任何重復,即原始陣列中的不同值不能更新為相同的隨機整數。這些值目前在 0 到 9000 之間的連續范圍內。陣列中的值相當多;
np.amax(arr) #output = 9000
于是嘗試了下面的方法...
max_v = np.amax(arr)
vlist = []
for l in range(1,max_v): vlist.append(l)
for l in tqdm(range(1,max_v)):
m = random.randint(1,len(vlist))
n = vlist[m]
arr = np.where(arr == l, n, arr)
vlist.remove(n)
我當前的代碼每次迭代大約需要 13 秒,有 9000 次迭代(至少前幾次迭代太慢了)。我曾考慮過使用 concurrent.futures 進行并行化,但我敢肯定我很可能在這里錯過了一些明顯的東西 XD
uj5u.com熱心網友回復:
如果您當前的值在一個連續范圍內,并且您想要另一個連續范圍,那么您很幸運!那時,您并沒有真正生成 20 億個亂數:您只是在置換 9000 個左右的整數。例如:
arr = np.random.randint(9001, size=(10, 20, 20))
p = np.arange(arr.max(None) 1)
np.random.shuffle(p)
arr = p[arr]
替換值不必從零開始,但如果您打算迭代地執行此操作,則必須先減去偏移量,然后再將arr其用作p.
uj5u.com熱心網友回復:
正如瘋狂物理學家所建議的,這是我幾乎相同的解決方案:
from sys import getsizeof
import numpy as np
# create a new-style random generator
rng = np.random.default_rng()
# takes ~20 seconds, ~60 secs with legacy generator
X = rng.integers(9001, size=(2000, 1000, 1000), dtype=np.uint16)
# output: 3.73 GiB, uint16 takes 1/4 space of the default int64
print(f"{getsizeof(X) / 2**30:.2f} GiB")
# generate a permutation, converting to same datatype makes slightly faster
p = rng.permutation(np.max(X) 1).astype(X.dtype)
# iterate applying permutation, takes ~10 seconds in total
for i in range(len(X)):
X[i] = p[X[i]]
我在應用排列時進行迭代,以減少瞬態記憶體需求。它一次只需要第一個維度的一個切片(~2MiB),而不是嘗試再次完全分配一個新副本。
MadPhysicist 問我為什么在for最后做回圈而不是直接執行X[:] = p[X]. 這是關于減少程式的記憶體需求。在 Linux 下,我會使用類似的東西:
from resource import getrusage, RUSAGE_SELF
print(getrusage(RUSAGE_SELF).ru_maxrss)
告訴我已分??配給 Python 行程的最大 RAM(以 KiB 為單位)。如果我在運行上面的代碼后運行它,我會3938904列印出來,所以 3.76GiB。如果我不使用for回圈,那么它會上升到 7.48 GiB。如果我不能確保排列也是型別uint16(即 with .astype(X.dtype)),那么我的筆記本電腦將開始交換,因為它需要超過 16GiB 的 RAM。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/530660.html
上一篇:For回圈賦值
