【问题标题】:python multidimensional boolean array?python多维布尔数组?
【发布时间】:2012-11-16 20:35:13
【问题描述】:

它最多包含 1000 x 1000 x 1000 个元素,这对于 python 字典来说太大了。

使用 dict,大约 30 x 1000 x 1000 元素,在我的机器上它已经消耗了 2gb 的内存并且所有东西都被扔掉了。

是否有任何模块可以处理其值仅为 True/False 的 3 维数组?我检查了 bitarray http://pypi.python.org/pypi/bitarray,它看起来很合理并且用 C 编码,但是它看起来更像是一个比特流而不是一个数组,因为它只支持一维。

【问题讨论】:

  • 您可以创建一个bitarray,然后自己进行索引。
  • 在许多编程环境中,人们使用“数组”是指“一个只有一维的数组”,而不是更一般的含义。这就是为什么你经常发现人们在做数组的数组(listlists 的 bitarrays)或伪造一维数组中的 ND 数组(a[z*1000*1000+y*1000+x] 而不是 a[x, y, z])——因为它们并没有真正的通用数组类型,只有一维数组类型。

标签: python arrays boolean


【解决方案1】:

numpy 是你的朋友:

import numpy as np
a = np.zeros((1000,1000,1000), dtype=bool)
a[1,10,100] = True

尽可能少地占用内存。

编辑:

如果你真的需要,你也可以查看 collections 模块中的 defaultdict 类容器,它不存储默认值的值。但如果不是必须的,请使用 numpy。

【讨论】:

  • 我对您的编辑感到困惑。你是什​​么意思“不存储给定值的值”?我想你可能不明白 defaultdict 究竟是什么或做什么。
  • 我认为编辑意味着你可以将默认值设置为true或false,然后只需要存储另一个位置。基本上是一个稀疏数组。
  • 正如@tcaswell 所说,我指的是默认字典的默认值集。这不是我最好的英语时刻,这是肯定的。
  • 恕我直言,我认为 尽可能少地占用内存 具有误导性。 AFAIK 每个布尔值需要一个字节。
【解决方案2】:

位数组列表的列表怎么样,也许用一个不错的 API 封装到您自己的类中?

或者,一个 3D NumPy 整数数组,您自己的代码将多个布尔值打包/解包到每个整数中。

【讨论】:

  • +1。但是,当您可以使用 numpy 的 bool 数组为您执行此操作时,您无需手动将内容打包到 numpy 整数数组中。
  • @abarnert:你确定吗?我认为 NumPy 会使用一个字节——而不是一个位——每个布尔值。你是说不是这样吗?
  • 我没有测试过。我不认为我曾经将numpy 用于bool 值......但是IIRC,很久以前使用numeric 你必须对1 位布尔数组和8 位布尔数组使用不同的类型,所以你可以好吧。 (无论如何,即使是 1 字节的值也会下降到刚刚超过 1GB 而不是 6GB……)
  • 而不是猜测:numpy.zeros(1000, 1000, 1000, dtype=bool).dtype 返回1000000000,1GB,所以看起来你是对的。
  • 但看起来您可以使用packbits 将其中一个维度打包成位。您可能必须解包切片等才能实际使用数据;我以前从来没有用过这个。但它仍然可能比在任何地方编写自己的打包/解包代码更容易。
【解决方案3】:

numpy 已经被 EnricoGiampieri 推荐过,如果你可以使用它,你应该这样做。

否则,有两种选择:

按照 NPE 的建议,锯齿状数组将是 listlistbitarrays。这允许你有锯齿状的边界——例如,每一行可以是不同的宽度,甚至可以独立调整大小:

bits3d = [[bitarray.bitarray(1000) for y in range(1000)] for x in range(1000)]
myvalue = bits3d[x][y][z]

或者,按照 Xymotech 的建议,对一维数组进行自己的索引:

bits3d = bitarray.bitarray(1000*1000*1000)
myvalue = bits3d[x + y*1000 + z*1000*1000]

无论哪种方式,您都可能希望将其封装在一个类中,这样您就可以这样做:

bits3d = BitArray(1000, 1000, 1000)
myvalue = bits3d[x, y, z]

这很简单:

class Jagged3DBitArray(object):
    def __init__(self, xsize, ysize, zsize):
        self.lll = [[bitarray(zsize) for y in range(ysize)] 
                    for x in range(xsize)]
    def __getitem__(self, key):
        x, y, z = key
        return self.lll[x][y][z]
    def __setitem__(self, key, value):
        x, y, z = key
        self.lll[x][y][z] = value

class Fixed3DBitArray(object):
    def __init__(self, xsize, ysize, zsize):
        self.xsize, self.ysize, self.zsize = xsize, ysize, zsize
        self.b = bitarray(xsize * ysize * zsize)
    def __getitem__(self, key):
        x, y, z = key
        return self.b[x + y * self.ysize + z * self.ysize * self.zsize]
    def __setitem__(self, key, value):
        x, y, z = key
        self.b[x + y * self.ysize + z * self.ysize * self.zsize] = value

当然,如果你想要更多的功能(比如切片),你必须多写一点。

锯齿状数组会使用更多内存(毕竟,您有 1M bitarray 对象和 1K list 对象的开销),并且可能会慢一些,但这通常不会有太大区别.

重要的决定因素应该是您的数据是否存在锯齿状行本质上的错误。如果是这样,请使用第二种解决方案;如果有锯齿状或可调整大小的行可能有用,请使用前者。 (请记住,如果可能的话,我会在任一解决方案上使用 numpy。)

【讨论】:

    【解决方案4】:

    如何从 unix 文件权限中获得灵感? 755 是为所有者读取、写入、执行和为其他所有人读取、执行的。这是因为7 转换为二进制111

    因此,您的 1000x1000x1000 布尔数组可以是一个 1000x1000 的 ints 列表,其中每个 int 的二进制表示为您提供一个代表布尔数组的 1000“位”字符串。

    所有这些都应该适合 1GB 的内存

    【讨论】:

    猜你喜欢
    • 2017-11-17
    • 1970-01-01
    • 2019-06-18
    • 2015-04-10
    • 2018-04-01
    • 1970-01-01
    • 2022-01-23
    • 2016-04-11
    • 2021-09-12
    相关资源
    最近更新 更多