【问题标题】:Create large random boolean matrix with numpy使用 numpy 创建大型随机布尔矩阵
【发布时间】:2017-09-17 15:00:57
【问题描述】:

我正在尝试创建一个巨大的boolean 矩阵,该矩阵以给定的概率p 随机填充TrueFalse。一开始我用的是这段代码:

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 条目的概率为 pFalse 条目的概率为 1-p

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

【问题讨论】:

  • 无法理解该部分 - does not seem to terminate for this big N。澄清一下?
  • 为什么是布尔数组但不设置数据类型?并检查您的内存是否足够。否则垃圾会减慢每一种方法。
  • 一旦内存耗尽,机器会变慢吗?
  • @Serge 但是为什么呢?我的意思是:我在第 3 行创建 NxN 数组 - 所以内存没有理由耗尽。此外,内存真的没问题,因为机器里有很多 - 大约 0.5 TB。
  • @FlashTek:在您写入之前,您的操作系统实际上不会将 RAM 提交给该分配。

标签: python numpy random


【解决方案1】:

问题在于您的 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,而函数方法保留所有它。

【讨论】:

    【解决方案2】:

    所以我尝试通过这样做将其拆分为单行的生成:

    np.random.choice 的工作方式是首先在[0, 1) 中为数据的每个单元格生成float64,然后使用np.search_sorted 将其转换为数组中的索引。这个中间表示比布尔数组大 8 倍!

    由于您的数据是布尔值,因此您可以获得两倍的加速

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

    这很自然,您可以在循环解决方案中使用

    似乎np.random.choice 可以在这里做一些缓冲 - 你可能想针对 numpy 提出问题。

    另一种选择是尝试生成float32s 而不是float64s。我不确定 numpy 现在是否可以做到这一点,但您可以请求该功能。

    【讨论】:

    • 好的,很有趣——np.random.rand(N, N) > p 的解决方案是我的第一个想法,我放弃了,因为我认为直接 numpy 调用会更快。
    • @FlashTek:问题是np.random.choice 必须做更多的工作,因为它必须处理两个以上结果的案例。 Definitely scope for a special case when the number of choices is two
    • 好的。但是你知道为什么我的第一篇文章会出现这种放缓吗?
    • 哪种减速?第二次尝试更快的原因是因为您没有一次分配所有浮点数,而且它们比最终结果大得多。
    • 不,我的意思是第二次尝试的减速发生在第 1100 行生成之后 - 如上所述。
    【解决方案3】:

    另一种可能性是批量生成它(即计算许多子数组并在最后将它们堆叠在一起)。但是,请考虑不要像 OP 那样在 for 循环中更新一个数组 (mask)。这将强制整个数组在每次索引更新期间加载到主内存中。

    例如:要获得30000x30000,有9000 个100x100 单独的数组,在for 循环中相应地更新每个100x100 数组,最后将这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)
    

    【讨论】:

      猜你喜欢
      • 2016-12-16
      • 1970-01-01
      • 2013-12-01
      • 2020-07-13
      • 2016-11-20
      • 2016-04-14
      • 2017-04-16
      • 2014-06-20
      • 1970-01-01
      相关资源
      最近更新 更多