三维数组与稀疏数据的稀疏矩阵

时间:2013-02-28 20:23:38

标签: python arrays data-structures sparse-matrix

我正在构建一个银河系的简单模型,我需要存储的一个东西是质量密度的3D网格。

问题在于,如果我在星系周围放置一个矩形框,大多数网格单元都是空的。这让我省去了很多无用的零。所以天真阵列似乎很浪费:

galaxy = [[[0 for k in xrange(1601)] for j in xrange(1601)] for i in xrange(253)]
# then fill in i,j,k values that are non-zero

我尝试使用字典构建稀疏数组:

for x in range(1601):
    for y in range(1601):
        for z in range (253):
            galaxy[str(x) + "," + str(y) + "," + str(z)] = # whatever

但是,(除了丑陋)我用于键的字符串占用的内存比我保存的更多。我得到了OutOfMemoryError因为(我计算过)单独的密钥需要几个记忆。

在某些时候,我会想要提高我的模型的分辨率,这将意味着更大的网格。 存储我的值的方法是否比使用3D数组浮点数更有效?

我还担心迭代所有单元格(或者只是网格中的非零单元格所需的时间。这将非常重要。

3 个答案:

答案 0 :(得分:2)

尝试使用字典方法,但只存储值为非零的键的值:值对。更好的密钥可能是(x,y,z)的元组。

答案 1 :(得分:2)

快速数学:1601 * 1601 * 253 => 648489853 items。测试表明字典在32位机器上每个条目大约需要24个字节,在64位机器上需要49个字节,所以这是 15,563,756,472字节(或64位时30GB)。其中10%是1.5GB(或64位时为3.0GB)。如果你有一个带有大量内存的64位系统,我认为你可以使用稀疏表示。

我建议:

  1. 使用元组作为键,而不是字符串,
  2. 使用稀疏存储系统,不存储零值。
  3. 这是一种可能性:

    class SparseDict(dict):
      def __init__(self, default_value):
        dict.__init__(self)
        self._value = default_value
      def __getitem__(self, key):
        try:
          return dict.__getitem__(self, key)
        except KeyError:
          return self._value
      def __setitem__(self, key, val):
        # I'm sure this can go faster if I were smarter
        if val == self._value:
          if  key in self:
            del self[key]
        else:
          dict.__setitem__(self, key, val)
    
    def test(galaxy):
      import sys
      print len(galaxy), sys.getsizeof(galaxy)
    
      # test is 1/10th size in each dimension,
      # so 1/1000th of the volume
      for x in range(160):
        for y in range(160):
          for z in range (25):
            import random
            # 90% of space is essentially a vacuum
            if random.random() < .1:
              galaxy[x,y,z] = 1502100
            else:
              galaxy[x,y,z] = 0
    
      print len(galaxy), sys.getsizeof(galaxy)
    
    test(SparseDict(0))
    

答案 2 :(得分:0)

也许尝试将数据保存在sql表中,并根据需要仅加载多维数据集的子集。这将花费你及时加载零件,但会节省你的记忆。至于内存重新定位,请使用其他答案中建议的方法,如字典等......