2017-03-03 7 views
3

週の奇妙な日に、私はnumpyで多次元索引付けをほぼ理解しています。 Numpyの機能は'take'ですが、私が望むことをしているようですが、インデックスが乱れていると何が起こるのかを制御できるという特典があります 具体的には、ルックアップテーブルとして質問する3次元配列numpy多次元索引付けと関数 'take'

私は、 lut[arr] arrを記述した場合、テーブルに
lut = np.ones([13,13,13],np.bool) 

および索引として作用する3-長いベクトルの2×2アレイ

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

IIUC、数字の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?) 

を書いて、今3つの用語は、彼らがタプルの2x2の配列を生成するためにzip形式で圧縮されているとlut[<tuple>]lutから単一の要素を生成しているかのよう行動することで、それは私がやりたいことができます。最終的な結果は、lutからのエントリの2x2配列です。ちょうど私が欲しいものです。

私は、この機能は「空想」のインデックス (配列を使用してインデックスアレイ)と同じことをし...

「を取る」関数のドキュメントを読んでいます。ただし、指定された軸に沿って要素が必要な場合は、 を使用する方が簡単です。

軸:INT、任意
値を選択する上軸。

はおそらく、単純に、私は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画像を持っていたと私はそれのパッチを同定したことでした。私はこのパッチ内のピクセルのセットを取り、それらのいずれかと一致するイメージ全体のすべてのポイントにマークを付けたいと思っていました。 256x256x256の存在テーブルが大きすぎるため、パッチのピクセル上でクラスタリングアルゴリズムを実行し、各クラスタの存在テーブルを設定しました(パッチの色はrgbまたはhsvスペースを介して細いスレッドを形成し、クラスタ周辺のボックス小さかった)。

私は存在テーブルを必要以上にわずかに大きくし、各面をFalseで埋めます。

これらの小さな存在テーブルを設定したら、残りの画像をテストして、テーブル内の各ピクセルをルックアップしてパッチを照合し、クリップを使用して通常はテーブルは実際にテーブルの面にマッピングされます(値は「False」になります)

2

私たちは、線形インデックスを計算し、その後np.take使用することができます - それをデータ配列に、タプルにインデックスを変換し、我々は2Dにインデックス配列を再構築することができ、あなたは選択肢に開かれている場合

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

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

サンプル実行 - -

012私たちに 2Dに戻って再整形することができ 1Dを与えるために私たちはそうのように、 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のDivaCarの解決策 –

0

私は3次元で試しませんでした。おそらく、あなたは3次元にそれを拡張することができます

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

:しかし2次元に私はnumpy.takeを使用して欲しい結果を得ることができます。リーン書き込みに紹介Iは指数IXのための2つの1次元の配列でアドレス離散ラプラス方程式の2次元ステンシルをIYできとして

Δ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) 
関連する問題