3

我正在构建一个简单的银河系模型,我需要存储的东西之一是质量密度的 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

但是,(除了丑陋之外)我用于键的字符串占用的内存比我节省的要多。我得到OutOfMemoryErrors 是因为(我计算出)键本身就占用了几场内存。

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

我还担心遍历所有单元格(或仅是网格中的非零单元格)所花费的时间。这将非常重要。

4

3 回答 3

2

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

于 2013-02-28T20:27:29.543 回答
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. 使用不存储零值的稀疏存储系统。

这是一种可能性:

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))
于 2013-02-28T21:16:40.860 回答
0

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

于 2013-02-28T20:36:36.403 回答