我正在尝试创建一个巨大的boolean
矩阵,该矩阵随机填充True
和False
,给定概率为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,这不会成为问题。
答案 0 :(得分:9)
问题在于你的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
请注意,掩码方法在其峰值时仅占用约9GB的RAM。
编辑:第一个方法在完成该过程后刷新RAM,其中函数方法保留所有内容。
答案 1 :(得分:4)
所以我尝试通过这样做将它分成单行的生成:
np.random.choice
的工作方式是首先在float64
为数据的每个单元格生成[0, 1)
,然后使用{{1}将其转换为数组中的索引}。这个中间表示比布尔数组大8倍!
由于您的数据是布尔值,因此您可以使用
获得两倍的加速np.search_sorted
当然,您可以在循环解决方案中使用
似乎np.random.rand(N, N) > p
可以在这里进行一些缓冲 - 您可能想要针对numpy提出问题。
另一种选择是尝试生成np.random.choice
而不是float32
s。我不确定numpy现在是否能做到这一点,但你可以请求这个功能。
答案 2 :(得分:0)
另一种可能性是批量生成它(即计算许多子阵列并在最后将它们堆叠在一起)。但是,考虑不要像OP那样在mask
循环中更新一个数组(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)