多维和线性索引之间的Numpy相互转换 [英] Numpy interconversion between multidimensional and linear indexing

查看:21
本文介绍了多维和线性索引之间的Numpy相互转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一种在 Numpy 中线性索引和多维索引之间相互转换的快速方法.

I'm looking for a fast way to interconvert between linear and multidimensional indexing in Numpy.

为了具体说明我的用法,我有大量 N 个粒子,每个粒子都分配了 5 个浮点值(维度),给出了一个 Nx5 数组.I then bin each dimension using numpy.digitize with an appropriate choice of bin boundaries to assign each particle a bin in the 5 dimensional space.

To make my usage concrete, I have a large collection of N particles, each assigned 5 float values (dimensions) giving an Nx5 array. I then bin each dimension using numpy.digitize with an appropriate choice of bin boundaries to assign each particle a bin in the 5 dimensional space.

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

binassign 然后包含对应于多维索引的行.如果然后我想将多维索引转换为线性索引,我想我想做类似的事情:

binassign then contains rows that correspond to the multidimensional index. If I then want to convert the multidimensional index to a linear index, I think I would want to do something like:

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

这将查找每个多维索引以将其映射到线性索引.然后您可以返回使用:

This would give a look-up for each multidimensional index to map it to a linear index. You could then go back using:

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

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

Where I'm having difficulties is figuring out how to take binassign (the Nx5 array) containing the multidimensional index in each row, and coverting that to an 1d linear index, by using it to slice the linear indexing array linind.

如果有人有一个(或多个)线索引技巧,可以以矢量化所有 N 个粒子的操作的方式在多维索引和线性索引之间来回切换,我将不胜感激.

If anyone has a one (or several) line indexing trick to go back and forth between the multidimensional index and the linear index in a way that vectorizes the operation for all N particles, I would appreciate your insight.

推荐答案

虽然我非常喜欢 EOL 的答案,但我想将其概括为沿每个方向的非均匀数量的 bin,并强调两者之间的差异C 和 F 样式的排序.这是一个示例解决方案:

Although I very much like EOL's answer, I wanted to generalize it a bit for non-uniform numbers of bins along each direction, and also to highlight the differences between C and F styles of ordering. Here is an example solution:

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)

为了完整起见,如果您想以一种快速的矢量化方式从一维索引返回到多维索引:

And for completeness, if you want to go back from the 1d index to the multidimensional index in a fast, vectorized-style way:

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 

这篇关于多维和线性索引之间的Numpy相互转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆