2017-03-03 36 views
3

在本周的奇怪日子里,我几乎可以理解numpy中的多维索引。 NumPy的具有功能'take'这似乎做我想做的,但有额外的奖励,我可以控制,如果索引超出rangect 具体发生了什么,我有一个3维数组问的查找表numpy多维索引和函数'take'

lut = np.ones([13,13,13],np.bool) 

和3-长矢量的2×2阵列充当索引到表

arr = np.arange(12).reshape([2,2,3]) % 13 

IIUC,如果我是写lut[arr]然后arr被视为数字的2x2x3阵列和这些使用时作为索引到lut他们每个返回一个13x13阵列。这解释了为什么lut[arr].shape is (2, 2, 3, 13, 13)

我可以通过写

lut[ arr[:,:,0],arr[:,:,1],arr[:,:,2] ] #(is there a better way to write this?) 

,现在这三个方面作为,如果他们已经进行了压缩,以产生一个元组的2x2的阵列和lut[<tuple>]lut产生一个单一的元素让它做我想做的。最后的结果是一个来自lut的2x2数组条目,正是我想要的。

我已经阅读了“采取”函数的文档...

这个函数做同样的事情,“花哨”索引 (使用数组索引阵列);但是,如果您需要沿给定轴的元素,则使用 更容易。

轴:整数,可选
在其上选择值的轴线。

也许天真,我以为设置axis=2我会得到三个值作为3元组使用进行查找,但实际上

np.take(lut,arr).shape = (2, 2, 3) 
np.take(lut,arr,axis=0).shape = (2, 2, 3, 13, 13) 
np.take(lut,arr,axis=1).shape = (13, 2, 2, 3, 13) 
np.take(lut,arr,axis=2).shape = (13, 13, 2, 2, 3) 

所以很显然,我不明白是怎么回事上。任何人都可以告诉我如何实现我想要的?

回答

0

原来的问题试图做一个查找表中的,但 一些指标是出界,我想控制 行为时,这发生过。

import numpy as np 
lut = np.ones((5,7,11),np.int) # a 3-dimensional lookup table 
print("lut.shape = ",lut.shape) # (5,7,11) 

# valid points are in the interior with value 99, 
# invalid points are on the faces with value 0 
lut[:,:,:] = 0 
lut[1:-1,1:-1,1:-1] = 99 

# set up an array of indexes with many of them too large or too small 
start = -35 
arr = np.arange(start,2*11*3+start,1).reshape(2,11,3) 

# This solution has the advantage that I can understand what is going on 
# and so I can amend it if I need to 

# split arr into tuples along axis=2 
arrchannels = arr[:,:,0],arr[:,:,1],arr[:,:,2] 

# convert into a flat array but clip the values 
ravelledarr = np.ravel_multi_index(arrchannels, lut.shape, mode='clip') 

# and now turn back into a list of numpy arrays 
# (not an array of the original shape) 
clippedarr = np.unravel_index(ravelledarr, lut.shape) 
print(clippedarr[0].shape,"*",len(clippedarr)) # produces (2, 11) * 3 

# and now I can do the lookup with the indexes clipped to fit 
print(lut[clippedarr]) 

# these are more succinct but opaque ways of doing the same 
# due to @Divakar and @hjpauli respectively 
print(np.take(lut, np.ravel_multi_index(arr.T, lut.shape, mode='clip')).T) 
print(lut.flat[np.ravel_multi_index(arr.T, lut.shape, mode='clip')].T) 

实际应用的是,我有一些含有木质纹理与它的一些标记的RGB图像,我已经确定了它的补丁。我想借此设定这个补丁中的像素并标出匹配他们中的一个在整个图像中所有的点。甲255x255x255种存在表太大所以我跑从贴剂中的像素的聚类算法和设置存在表对于每个簇(从贴片的颜色而形成的细长的螺纹通过RGB-或HSV-空间,以便围绕所述簇的框很小)。

我做比所需稍大的存在表并填写每个面有假。

一旦我已经设置了这些小表存在我现在可以测试图像的其余部分通过查找表中的每个像素块匹配,并使用裁剪,使通常不会映射到像素表实际上映射到一个面表(并获得值“假”)

2

我们可以计算线性指标,然后使用np.take -

np.take(lut, np.ravel_multi_index(arr.T, lut.shape)).T 

如果你是开放的替代方案,我们可以把指数阵列重塑到2D,转换成元组,索引数据阵列有了它,给我们1D,这可能是重塑回2D -

lut[tuple(arr.reshape(-1,arr.shape[-1]).T)].reshape(arr.shape[:2]) 

采样运行 -

In [49]: lut = np.random.randint(11,99,(13,13,13)) 

In [50]: arr = np.arange(12).reshape([2,2,3]) 

In [51]: lut[ arr[:,:,0],arr[:,:,1],arr[:,:,2] ] # Original approach 
Out[51]: 
array([[41, 21], 
     [94, 22]]) 

In [52]: np.take(lut, np.ravel_multi_index(arr.T, lut.shape)).T 
Out[52]: 
array([[41, 21], 
     [94, 22]]) 

In [53]: lut[tuple(arr.reshape(-1,arr.shape[-1]).T)].reshape(arr.shape[:2]) 
Out[53]: 
array([[41, 21], 
     [94, 22]]) 

我们能避免双变调为np.take方法,像这样 -

In [55]: np.take(lut, np.ravel_multi_index(arr.transpose(2,0,1), lut.shape)) 
Out[55]: 
array([[41, 21], 
     [94, 22]]) 

推广到多维的通用尺寸

这可以推广到一般没有ndarrays的阵列。像这样 -

np.take(lut, np.ravel_multi_index(np.rollaxis(arr,-1,0), lut.shape)) 

tuple-based方法应该没有任何改变。

这里有一个相同的样品运行 -

In [95]: lut = np.random.randint(11,99,(13,13,13,13)) 

In [96]: arr = np.random.randint(0,13,(2,3,4,4)) 

In [97]: lut[ arr[:,:,:,0] , arr[:,:,:,1],arr[:,:,:,2],arr[:,:,:,3] ] 
Out[97]: 
array([[[95, 11, 40, 75], 
     [38, 82, 11, 38], 
     [30, 53, 69, 21]], 

     [[61, 74, 33, 94], 
     [90, 35, 89, 72], 
     [52, 64, 85, 22]]]) 

In [98]: np.take(lut, np.ravel_multi_index(np.rollaxis(arr,-1,0), lut.shape)) 
Out[98]: 
array([[[95, 11, 40, 75], 
     [38, 82, 11, 38], 
     [30, 53, 69, 21]], 

     [[61, 74, 33, 94], 
     [90, 35, 89, 72], 
     [52, 64, 85, 22]]]) 
+0

对于它的价值,'np.take'等同于对'lut.flat'进行索引:'lut.flat [np.ravel_multi_index(arr.T,lut.shape)]。T' – hpaulj

+0

谢谢无论是为您的解决方案由于ravel_multi_index允许剪辑,我根本不需要'take',所以我将使用@ hjpauli对Divakar解决方案的修正 –

0

我没有在3维尝试。但在2维我得到了我想要使用numpy.take结果:

np.take(np.take(T,ix,axis=0), iy,axis=1) 

也许你可以扩展到3维。

作为示例我可以与用于索引IX两个1暗淡阵列ADRESS和IY为离散拉普拉斯方程2维模版,

ΔT = T[ix-1,iy] + T[ix+1, iy] + T[ix,iy-1] + T[ix,iy+1] - 4*T[ix,iy] 

为精简写入介绍:

def q(Φ,kx,ky): 
    return np.take(np.take(Φ,kx,axis=0), ky,axis=1) 

然后我可以numpy.take运行以下Python代码

nx = 6; ny= 10 
T = np.arange(nx*ny).reshape(nx, ny) 

ix = np.linspace(1,nx-2,nx-2,dtype=int) 
iy = np.linspace(1,ny-2,ny-2,dtype=int) 

ΔT = q(T,ix-1,iy) + q(T,ix+1,iy) + q(T,ix,iy-1) + q(T,ix,iy+1) - 4.0 * q(T,ix,iy)