使用 numpy 创建大型随机布尔矩阵

新手上路,请多包涵

I am trying to create a huge boolean matrix which is randomly filled with True and False with a given probability 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 行的生成速度非常快——但之后,代码变得非常慢。为什么会这样?我在这里想念什么? Are there better ways to create a big matrix which has True entries with probability p and False entries with probability 1-p ?

编辑:你们中的许多人都认为 RAM 会是个问题:因为运行代码的设备有将近 500GB 的 RAM,所以这不会成为问题。

原文由 zimmerrol 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1k
2 个回答

真的很惊讶还没有人提到这个解决方案..

这条线

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

运行 NXN 伯努利试验。 (在你的例子中,有 900M!)伯努利试验只是一个随机试验,有两种可能的结果,概率为 p 和 1-p。

n 个伯努利试验的总和,每个试验的概率为 p,可以用 二项分布 建模。

我们可以利用这个事实来随机模拟 True 元素的总数。使用 NumPy,

 import numpy as np

N = 30000
p = 0.1

# Build a random number generator
rng = np.random.default_rng(123)

# Randomly determine the total number of True values
Ntrue = rng.binomial(n=N*N, p=p, size=1)[0]  # 90016776

现在我们可以通过随机选择 row 和 col 索引 而不用替换 来随机确定每个 True 元素的 _位置_。

 # Randomly determine true position
position_ids = rng.choice(a=N*N, size=Ntrue, replace=False)
positions = np.unravel_index(position_ids, shape=(N,N))

现在我们可以填充压缩稀疏行 (CSR) 矩阵。

 from scipy import sparse

# Build a compressed sparse row matrix with the constructor:
# csr_matrix((data, (row_ind, col_ind)), [shape=(M, N)])
result = sparse.csr_matrix((np.ones(shape=Ntrue), positions), shape=(N,N))

请注意,此解决方案避免了存储 和计算 900M 布尔值。

有趣的是,在偶然发现这个 问题之前,我写了一个几乎相同 的问题。

原文由 Ben 发布,翻译遵循 CC BY-SA 4.0 许可协议

问题是您的 RAM,值在创建时存储在内存中。我刚刚使用这个命令创建了这个矩阵:

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

我使用了一个 AWS i3 具有 64GB RAM 和 8 个内核的实例。要创建此矩阵, 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,因为函数方法保留了所有内容。

原文由 gold_cy 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题