2012-06-19 12 views
6

2次元の2つの配列があり、列ベクトルは特徴ベクトルです。欲しいnumpy配列間の距離、列方向

arr1 = np.array([[1, 4], 
        [2, 5], 
        [3, 6]]) 

arr2 = np.array([[1, 4, 7, 10, ..], 
        [2, 5, 8, 11, ..], 
        [3, 6, 9, 12, ..]]) 

:つのアレイは、Fは、A、A = 2、F = 3 < < B.例として、(Bは何であってもよい)のFのX B、の他のxは大きさであります可能なフラグメントのそれぞれについて、arr2の等しいサイズ(この場合は3x2)であるarr1arr2のフラグメントの間の距離を計算する。列ベクトルは互いに独立しているので、arr1の各列ベクトルと、ii + Aからarr2までの範囲の列ベクトルのコレクションを計算し、これらの距離の合計を取る必要があると確信しています。

numpyは効率的な方法ですが、2番目の配列からスライスを取り、別のループを使用して、各列ベクトルの距離をarr1で計算し、スライスの対応する列ベクトルを計算する必要がありますか?上記の配列を使用して明確にするため

例は、:それはcdistが何とかここで使用することができることを意味している場合もちろん

>>> magical_distance_func(arr1, arr2[:,:2]) 
[0, 10.3923..] 
>>> # First, distance between arr2[:,:2] and arr1, which equals 0. 
>>> # Second, distance between arr2[:,1:3] and arr1, which equals 
>>> diff = arr1 - np.array([[4,7],[5,8],[6,9]]) 
>>> diff 
[[-3, -3], [-3, -3], [-3, -3]] 
>>> # this happens to consist only of -3's. Norm of each column vector is: 
>>> norm1 = np.linalg.norm([:,0]) 
>>> norm2 = np.linalg.norm([:,1]) 
>>> # would be extremely good if this worked for an arbitrary number of norms 
>>> totaldist = norm1 + norm2 
>>> totaldist 
10.3923... 

、配列を転置することは、あまりにも結構です。

+0

興味深い質問、+1。 2つのフィーチャセットの関係が何であるか尋ねてもいいですか?一般的な解決策がない場合は、ドメイン固有の解決策が見つかる可能性があります。 –

+0

配列内の要素は、イメージ内の空間フィーチャの存在(または存在する場合はカウント)を示します。私は最も近いマッチを見つけようとしているので、分類タスクと見なすことができます。 'arr1'は、この場合、2つのタイムステップの短いシーケンスであり、Bタイムステップのドキュメントと比較して、最も近い一致シーケンスのインデックスを見つける。 –

答えて

4

私はあなたの質問を正しく理解すれば、これは動作します。 numpyを知っている方がいいでしょうが、これは少なくともと公平にです。計算が期待どおりに機能していることを示すために、いくつかの工夫した座標を使用しました。

>>> arr1 
array([[0, 3], 
     [1, 4], 
     [2, 5]]) 
>>> arr2 
array([[ 3, 6, 5, 8], 
     [ 5, 8, 13, 16], 
     [ 2, 5, 2, 5]]) 

あなたは、彼らが正しくお互いに放送することを保証することによりarr2からarr1を引くことができます。私が考えることができる最善の方法は、転置して、いくつかの形を変えることです。これらはコピーを作成しない - ビューを作成するので、無駄ではありません。 (distはしかしコピーです。)

>>> dist = (arr2.T.reshape((2, 2, 3)) - arr1.T).reshape((4, 3)) 
>>> dist 
array([[ 3, 4, 0], 
     [ 3, 4, 0], 
     [ 5, 12, 0], 
     [ 5, 12, 0]]) 

今、私たちがしなければならないすべては(あなたがnormsいくつかの中から選択することができます)1軸全体にnumpy.linalg.normを適用しています。あなたは、単純なユークリッド距離をしたいと仮定すると、

>>> numpy.apply_along_axis(numpy.linalg.norm, 1, dist) 
array([ 5., 5., 13., 13.]) 

、あなたも直接それを行うことができます。これが速くなったり遅くなりますかどうかを確認しますので、両方を試してみて:あなたの編集に基づいて

>>> (dist ** 2).sum(axis=1) ** 0.5 
array([ 5., 5., 13., 13.]) 

、我々は唯一の小さな微調整を行う必要があります。ブロック単位ではなくペア単位で列をテストしたいので、ローリングウィンドウが必要です。これはかなり簡単なインデックスを非常に簡単に行うことができます。

他のトリックであることを組み合わせる
>>> arr2.T[numpy.array(zip(range(0, 3), range(1, 4)))] 
array([[[ 3, 5, 2], 
     [ 6, 8, 5]], 

     [[ 6, 8, 5], 
     [ 5, 13, 2]], 

     [[ 5, 13, 2], 
     [ 8, 16, 5]]]) 

>>> arr2_pairs = arr2.T[numpy.array(zip(range(0, 3), range(1, 4)))] 
>>> dist = arr2_pairs - arr1.T 
>>> (dist ** 2).sum(axis=2) ** 0.5 
array([[ 5.  , 5.  ], 
     [ 9.69535971, 9.69535971], 
     [ 13.  , 13.  ]]) 

ただし、リスト内包からの配列を変換することは遅くなる傾向にあります。それstride_tricksを使用する方が速いかもしれない - ここで再び、最良のあなたの目的に合った1次を参照してください。

>>> as_strided(arr2.T, strides=(8, 8, 32), shape=(3, 2, 3)) 
array([[[ 3, 5, 2], 
     [ 6, 8, 5]], 

     [[ 6, 8, 5], 
     [ 5, 13, 2]], 

     [[ 5, 13, 2], 
     [ 8, 16, 5]]]) 

これは、実際に小さな配列が大きくをエミュレートすることができ、メモリのブロックの上にnumpy移動方法を操作しますアレイ。

>>> arr2_pairs = as_strided(arr2.T, strides=(8, 8, 32), shape=(3, 2, 3)) 
>>> dist = arr2_pairs - arr1.T 
>>> (dist ** 2).sum(axis=2) ** 0.5 
array([[ 5.  , 5.  ], 
     [ 9.69535971, 9.69535971], 
     [ 13.  , 13.  ]]) 

これで、列の各ペアの距離に対応する簡単な2次元配列ができました。今はmeanを取得してargminに電話するだけです。

+0

これは正確には私が探しているものではありませんが、あなたが作ったものを驚くほど素晴らしいものにしています。私がすべきであるほど明確でないことに対する私の謝罪。 arr1とarr2の同じサイズの各組み合わせ、つまり 'arr2'のインデックス(インデックス)を指定して、"ベストマッチ "を探しているので、出力はあなたが与えた配列例の3つの値から成ります。 'dist(arr2 [i:i + 2]、arr1)'が最小になるようにします。 –

+0

ああ、あなたはローリングウィンドウが必要です。私の編集を参照してください。 – senderle

+0

うわー。私が今までに聞いたことがないほど多くの機能を備えており、おそらくドキュメントの細かいスキャンの後にしか見つからなかったでしょう。どうもありがとう! –

1

scipy.spatial.distance.cdist?

+0

私は、arr1の各列がarr2の各列と比較される2つの配列間のユークリッド距離を計算すると考えています。 –

2

scipy.spatial.distanceからcdistを使用して距離行列を取得できます。距離行列を取得したら、列全体を合計し、平均距離を得るために正規化することができます。

注:列の代わりに、cdistは行を使用してペアの距離を計算します。ここで

あなたは「コサイン」の距離を使用する例があります。

from scipy.spatial.distance import cdist 

arr1 = np.array([[1, 7], 
       [4, 8], 
       [4, 0]]) 

arr2 = array([[1, 9, 3, 6, 2], 
       [3, 9, 0, 2, 3], 
       [6, 0, 2, 7, 4]]) 

# distance matrix 
D = cdist(arr1.transpose(), arr2.transpose(), 'cosine') 

# average distance array (each position corresponds to each column of arr1) 
d1 = D.mean(axis=1) 

# average distance array (each position corresponds to each column of arr2) 
d2 = D.mean(axis=0) 

# Results 
d1 = array([ 0.23180963, 0.35643282]) 
d2 = array([ 0.31018485, 0.19337869, 0.46050302, 0.3233269 , 0.18321265]) 

利用可能な多くの距離があります。 documentationをチェックしてください。

+0

この例をお寄せいただきありがとうございますが、私が探しているものではないと思います。私が探しているのは次のようなものです: 'arr1 = [[1,2]、[1,2]]、arr2 = [[1,2]、[1,2]、[1,3] arr2の最初のフラグメント '[[1,2]、[1,2]]がarr1と等しいため、' [0,1] ':0を返します。 2] 'と' [1,2] 'は0 +' 1,2]と[1,3]の間の距離であり、1です。 –

+0

これらの値を私の例に入れて、 D = [[0,0,1]、[0,0,1]]となります。たぶんこの結果をあなたの目的に使うことができますか? –

関連する問題