代码之家  ›  专栏  ›  技术社区  ›  JoshAdel

多维索引与线性索引的相互转换

  •  5
  • JoshAdel  · 技术社区  · 15 年前

    我正在寻找一种快速的方法来在Numpy的线性和多维索引之间进行转换。

    为了使我的用法具体化,我有一个N个粒子的大集合,每个粒子分配5个浮点值(维度),给出一个Nx5数组。然后我使用numpy.digitalize对每个维度进行分类,并选择适当的分类边界,在5维空间中为每个粒子指定一个分类。

    N = 10
    ndims = 5
    p = numpy.random.normal(size=(N,ndims))
    for idim in xrange(ndims):
        bbnds[idim] = numpy.array([-float('inf')]+[-2.,-1.,0.,1.,2.]+[float('inf')])
    
    binassign = ndims*[None]
    for idim in xrange(ndims):
        binassign[idim] = numpy.digitize(p[:,idim],bbnds[idim]) - 1
    

    linind = numpy.arange(6**5).reshape(6,6,6,6,6)
    

    这将为每个多维索引提供一个查找,以便将其映射到一个线性索引。然后您可以使用:

    mindx = numpy.unravel_index(x,linind.shape)
    

    我遇到的困难是如何获取每行中包含多维索引的二进制(Nx5数组),并将其转换为一维线性索引,方法是使用它对线性索引数组linind进行切片。

    如果有人有一个(或几个)线索引技巧来来回之间的多维指数和线性指数的方式,矢量化所有N粒子的操作,我会感谢你的洞察力。

    2 回复  |  直到 15 年前
        1
  •  4
  •   Eric O. Lebigot    15 年前

    您可以简单地计算每个箱子的索引:

    box_indices = numpy.dot(ndims**numpy.arange(ndims), binassign)
    

    标量积只做1*x0+5*x1+5*5*x2+这是通过NumPy的 dot() .

        2
  •  3
  •   JoshAdel    15 年前

    ndims = 5
    N = 10
    
    # Define bin boundaries 
    binbnds = ndims*[None]
    nbins = []
    for idim in xrange(ndims):
        binbnds[idim] = numpy.linspace(-10.0,10.0,numpy.random.randint(2,15))
        binbnds[idim][0] = -float('inf')
        binbnds[idim][-1] = float('inf')
        nbins.append(binbnds[idim].shape[0]-1)
    
    nstates = numpy.cumprod(nbins)[-1]
    
    # Define variable values for N particles in ndims dimensions
    p = numpy.random.normal(size=(N,ndims))
    
    # Assign to bins along each dimension
    binassign = ndims*[None]
    for idim in xrange(ndims):
        binassign[idim] = numpy.digitize(p[:,idim],binbnds[idim]) - 1
    
    binassign = numpy.array(binassign)
    
    # multidimensional array with elements mapping from multidim to linear index
    # Two different arrays for C vs F ordering
    linind_C = numpy.arange(nstates).reshape(nbins,order='C')
    linind_F = numpy.arange(nstates).reshape(nbins,order='F')
    

    现在进行转换

    # Fast conversion to linear index
    b_F = numpy.cumprod([1] + nbins)[:-1]
    b_C = numpy.cumprod([1] + nbins[::-1])[:-1][::-1]
    
    box_index_F = numpy.dot(b_F,binassign)
    box_index_C = numpy.dot(b_C,binassign)
    

    并检查其正确性:

    # Check
    print 'Checking correct mapping for each particle F order'
    for k in xrange(N):
        ii = box_index_F[k]
        jj = linind_F[tuple(binassign[:,k])]
        print 'particle %d %s (%d %d)' % (k,ii == jj,ii,jj)
    
    print 'Checking correct mapping for each particle C order'
    for k in xrange(N):
        ii = box_index_C[k]
        jj = linind_C[tuple(binassign[:,k])]
        print 'particle %d %s (%d %d)' % (k,ii == jj,ii,jj)
    

    print 'Convert C-style from linear to multi'
    x = box_index_C.reshape(-1,1)
    bassign_rev_C = x / b_C % nbins 
    
    print 'Convert F-style from linear to multi'
    x = box_index_F.reshape(-1,1)
    bassign_rev_F = x / b_F % nbins
    

    print 'Check C-order'
    for k in xrange(N):
        ii = tuple(binassign[:,k])
        jj = tuple(bassign_rev_C[k,:])
        print ii==jj,ii,jj
    
    print 'Check F-order'
    for k in xrange(N):
        ii = tuple(binassign[:,k])
        jj = tuple(bassign_rev_F[k,:])
        print ii==jj,ii,jj