2017-03-03 100 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)