numpy Python中的标志

izkcnapc  于 2022-12-23  发布在  Python
关注(0)|答案(6)|浏览(133)

我正在处理一个大型矩阵(250x250x30 = 1,875,000个单元格),我希望找到一种方法,以某种易于使用且合理节省空间的方式为该矩阵中的每个单元格设置任意数量的标志。
我最初的计划是一个250x250x30的列表数组,其中每个元素如下所示:["FLAG1","FLAG8","FLAG12"]。然后我将它改为只存储整数:[1,8,12]。这些整数由getter/setter函数在内部Map到原始的标志字符串。这只使用了250mb,每个点8个标志,这在内存方面是很好的。
我的问题是:我是否遗漏了另一种组织此类数据的明显方法?
谢谢大家的建议。我最终把几个建议揉成了一个,遗憾的是我只能选择一个答案,不得不接受其他的投票:
编辑:我这里的初始代码(使用集合作为3D numpy数组的基本元素)使用了大量的内存。这个新版本在填充randint(0,2**1000)时使用了大约500mb。

import numpy

FLAG1=2**0
FLAG2=2**1
FLAG3=2**2
FLAG4=2**3

(x,y,z) = (250,250,30)

array = numpy.zeros((x,y,z), dtype=object)

def setFlag(location,flag):
    array[location] |= flag
def unsetFlag(location,flag):
    array[location] &= ~flag
tquggr8v

tquggr8v1#

考虑使用Flyweight模式共享单元格属性:
http://en.wikipedia.org/wiki/Flyweight_pattern

tkclm6bt

tkclm6bt2#

BitSet正是您所需要的,因为它允许您仅使用一个固定大小的整数(Int类型)同时存储许多标志

nvbavucw

nvbavucw3#

把罗比的建议更进一步...

flags = set()
x, y, flag = 34, 201, 3
flags.add((x, y, flag)) # set flag 3 at position (34, 201)
if (3, 2, 1) in flags: # check if flag 1 is at position (3, 2)
    # do something
else:
    # do something else

您还可以创建一个helper类。

class Flags(object):
    def __init__(self):
        self.data = set()
    def add(self, x, y, flag):
        self.data.add((x, y, flag))
    def remove(self, x, y, flag):
        self.data.remove((x, y, flag))
    def contains(self, x, y, flag):
        return (x, y, flag) in self.data

你也可以实现Python的特殊方法,比如__contains__,使其更容易使用。

6pp0gazn

6pp0gazn4#

如果每一个单元格都有一个标志,那么你的解决方案就很好。但是,如果你使用的是稀疏数据集,其中只有一小部分单元格有标志,那么你真正需要的是字典。你可能希望设置字典,使键是单元格位置的元组,而值是一个标志列表,就像你在解决方案中所拥有的那样。

allFlags = {(1,1,1):[1,2,3], (250,250,30):[4,5,6]}

在这里,1,1单元格具有标志1、2和3,单元格250、250、30具有标志4、5和6
编辑-固定键元组,谢谢Andre,和字典语法。

ktca8awb

ktca8awb5#

我通常使用numpy数组(大概是短整型数,每个整型数2字节,因为您可能需要超过256个不同的值)--对于小于200万的单元格,这将占用不到4 MB的空间。
如果出于某种原因我无法承受 numpy 依赖(例如在App Engine上,它不支持numpy),我会使用标准库array模块--它只支持一维数组,但对于大型同构数组,它和numpy一样节省空间。您提到的getter/setter例程可以很好地“线性化”一个3项元组,它是您对一维数组的单个整数索引的自然索引。
一般来说,当您有大型齐次、密集向量或数字矩阵时,可以考虑numpy(或array)-- Python内置列表在这种情况下非常浪费空间(由于它们的通用性,您在这里没有使用也不需要!),节省内存也间接地转化为节省时间(更好的缓存、更少的间接层,等等)。

ahy6op9u

ahy6op9u6#

您可以将一些常数定义为不同的二次幂值,如下所示:

FLAG1 = 0x01
FLAG8 = 0x02
FLAG12 = 0x04
...

并将它们与布尔逻辑一起使用,以便仅将标志存储在一个整数中,例如:

flags = FLAG1 | FLAG8

要检查是否启用了标志,可以使用&运算符:

flag1_enabled = flags & FLAG1

如果启用了该标志,则此表达式将返回一个非零值,在任何布尔运算中该值都将被评估为True。如果禁用了该标志,则表达式将返回0,在布尔运算中该值将被评估为False。

相关问题