【问题标题】:Dimensionality agnostic (generic) cartesian product维度不可知(通用)笛卡尔积
【发布时间】:2014-08-30 03:30:37
【问题描述】:

我希望生成相对大量数组的笛卡尔积以跨越高维网格。由于高维,无法将笛卡尔积计算的结果存储在内存中;而是将其写入硬盘。由于这个限制,我需要在生成中间结果时访问它们。到目前为止,我一直在做的是:

for x in xrange(0, 10):
    for y in xrange(0, 10):
        for z in xrange(0, 10):
            writeToHdd(x,y,z)

除了非常讨厌之外,它是不可扩展的(即它需要我编写与维度一样多的循环)。我尝试使用here 提出的解决方案,但这是一个递归解决方案,因此很难在生成结果时即时获得结果。除了每个维度都有一个硬编码循环之外,还有什么“简洁”的方法可以做到这一点?

【问题讨论】:

    标签: python arrays numpy cartesian-product


    【解决方案1】:

    在普通 Python 中,您可以使用 itertools.product 生成可迭代集合的笛卡尔积。

    >>> arrays = range(0, 2), range(4, 6), range(8, 10)
    >>> list(itertools.product(*arrays))
    [(0, 4, 8), (0, 4, 9), (0, 5, 8), (0, 5, 9), (1, 4, 8), (1, 4, 9), (1, 5, 8), (1, 5, 9)]
    

    在 Numpy 中,您可以将 numpy.meshgrid(传递 sparse=True 以避免在内存中扩展乘积)与 numpy.ndindex 组合:

    >>> arrays = np.arange(0, 2), np.arange(4, 6), np.arange(8, 10)
    >>> grid = np.meshgrid(*arrays, sparse=True)
    >>> [tuple(g[i] for g in grid) for i in np.ndindex(grid[0].shape)]
    [(0, 4, 8), (0, 4, 9), (1, 4, 8), (1, 4, 9), (0, 5, 8), (0, 5, 9), (1, 5, 8), (1, 5, 9)]
    

    【讨论】:

      【解决方案2】:

      我想我想出了一个使用内存映射文件的好方法:

      def carthesian_product_mmap(vectors, filename, mode='w+'):
          '''
          Vectors should be a tuple of `numpy.ndarray` vectors. You could
          also make it more flexible, and include some error checking
          '''        
          # Make a meshgrid with `copy=False` to create views
          grids = np.meshgrid(*vectors, copy=False, indexing='ij')
      
          # The shape for concatenating the grids from meshgrid
          shape = grid[0].shape + (len(vectors),)
      
          # Find the "highest" dtype neccesary
          dtype = np.result_type(*vectors)
      
          # Instantiate the memory mapped file
          M = np.memmap(filename, dtype, mode, shape=shape)
      
          # Fill the memmap with the grids
          for i, grid in enumerate(grids):
              M[...,i] = grid
      
          # Make sure the data is written to disk (optional?)
          M.flush()
      
          # Reshape to put it in the right format for Carthesian product
          return M.reshape((-1, len(vectors)))
      

      但我想知道您是否真的需要存储整个 Carthesian 乘积(存在大量数据重复)。在需要时在产品中生成行不是一种选择吗?

      【讨论】:

      • 你也可以通过广播做作业,见stackoverflow.com/a/11146645/2379410
      • 只是出于好奇; Numpy memmap 会胜过基于数据库的解决方案吗?我猜数据库在建立连接等方面会有一些开销,但我认为数据库提供“智能”索引/压缩系统等?
      • @danielvdende,我没有数据库经验。也许当磁盘 IO 成为瓶颈时,它可能和 Numpy 一样快
      【解决方案3】:

      您似乎只想循环任意数量的维度。我的通用解决方案是使用索引字段和递增索引以及处理溢出。

      例子:

      n = 3 # number of dimensions
      N = 1 # highest index value per dimension
      
      idx = [0]*n
      while True:
          print(idx)
          # increase first dimension
          idx[0] += 1
          # handle overflows
          for i in range(0, n-1):
              if idx[i] > N:
                  # reset this dimension and increase next higher dimension
                  idx[i] = 0
                  idx[i+1] += 1
          if idx[-1] > N:
              # overflow in the last dimension, we are finished
              break
      

      给予:

      [0, 0, 0]
      [1, 0, 0]
      [0, 1, 0]
      [1, 1, 0]
      [0, 0, 1]
      [1, 0, 1]
      [0, 1, 1]
      [1, 1, 1]
      

      Numpy 内置了类似的东西:ndenumerate

      【讨论】:

      • 谢谢!事后看来很简单,就是想不通!
      • Gareth Rees 的答案的优点是它可以直接使用任意范围并使用内置函数。我更喜欢我的回答在简单的情况下也能解决问题。
      猜你喜欢
      • 2019-05-26
      • 1970-01-01
      • 2021-07-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多