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

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

问题描述

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

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

为了使我的用法具体化,我有大量的N个粒子,每个粒子分配5个浮点值(维度),给出一个Nx5数组。然后,我使用numpy.digitize并使用适当选择的bin边界来对每个维度进行分区,以便为每个粒子分配5维空间中的bin。

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到1d线性索引。

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的答案,但我想把它归结为非 - 沿着每个方向的均匀数量的箱子,并且还突出了订购的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)

对于co完整性,如果你想以快速,矢量化的方式从1d索引返回到多维索引:

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天全站免登陆