マンハッタン距離行列を作成するために、効率的なベクトル化されたnumpy
を実装しようとしています。私は次のようにドット積を使用して効率的なユークリッド距離行列を作成するために使用される構成に精通しています。
A = [[1, 2]
[2, 1]]
B = [[1, 1],
[2, 2],
[1, 3],
[1, 4]]
def euclidean_distmtx(X, X):
f = -2 * np.dot(X, Y.T)
xsq = np.power(X, 2).sum(axis=1).reshape((-1, 1))
ysq = np.power(Y, 2).sum(axis=1)
return np.sqrt(xsq + f + ysq)
私は同様のものを実装したいが、代わりにマンハッタン距離を使用したい。これまでのところ、私は近づきましたが、絶対的な違いを整理しようとして不足しました。マンハッタンの距離は
絶対関数がまったく適用されず、この等価性が得られないかどうかを検討することでこれを解決しようとしました
これは私に次のベクトル化を与えます
def manhattan_distmtx(X, Y):
f = np.dot(X.sum(axis=1).reshape(-1, 1), Y.sum(axis=1).reshape(-1, 1).T)
return f / Y.sum(axis=1) - Y.sum(axis=1)
私は正しい道だと思いますが、各ベクトル要素間の差の周りの絶対関数を削除せずに値を移動することはできません。おそらく2乗値のnp.sqrt
を使用するなどして、絶対値の周りに巧妙なトリックがあると確信していますが、それを実現できないようです。
ここでは要素ごとの乗算が行われていないため、ここではBLASベースの行列乗算を利用できないと思います。ただし、代替手段はほとんどありません。
アプローチ#1
Scipy's cdist
を使用できます。これには、オプションのメトリック引数を'cityblock'
-
from scipy.spatial.distance import cdist
out = cdist(A, B, metric='cityblock')
アプローチ#2-A
broadcasting
を利用することもできますが、より多くのメモリが必要です-
np.abs(A[:,None] - B).sum(-1)
アプローチ#2-B
これは、2つのcolsを持つ入力配列のスライスと合計を使用して、より少ないメモリを使用するように書き直すことができます-
np.abs(A[:,0,None] - B[:,0]) + np.abs(A[:,1,None] - B[:,1])
アプローチ#2-C
broadcasting
module -を使用したabsolute
バージョンの移植によるnumexpr
計算の高速化
import numexpr as ne
A3D = A[:,None]
out = ne.evaluate('sum(abs(A3D-B),2)')