2017-04-12 139 views
2

從另一個向量的每一列計算向量的歐幾里得。 這是正確的嗎?矩陣與向量之間的歐幾里德距離

new_v是矩陣。 val.reshape(10,1)是列向量。 另一種/更好的方法來做到這一點。

+0

'new_v'的形狀是什麼? – Divakar

+0

據推測,它是任意n的「(10,n)」。 – wim

+1

典型的'n'值會激發我們有一些時間:) – Divakar

回答

1

您可以使用的有效np.einsum -

subs = new_v - val[:,None] 
out = np.sqrt(np.einsum('ij,ij->j',subs,subs)) 

或者,使用(a-b)^2 = a^2 + b^2 - 2ab式 -

out = np.sqrt(np.einsum('ij,ij->j',new_v, new_v) + val.dot(val) - 2*val.dot(new_v)) 

如果new_v第二軸是一個大的,我們也numexpr模塊可以以最後計算sqrt部分。

運行測試

途徑 -

import numexpr as ne 

def einsum_based(new_v, val): 
    subs = new_v - val[:,None] 
    return np.sqrt(np.einsum('ij,ij->j',subs,subs)) 

def dot_based(new_v, val): 
    return np.sqrt(np.einsum('ij,ij->j',new_v, new_v) + \ 
          val.dot(val) - 2*val.dot(new_v)) 

def einsum_numexpr_based(new_v, val): 
    subs = new_v - val[:,None] 
    sq_dists = np.einsum('ij,ij->j',subs,subs) 
    return ne.evaluate('sqrt(sq_dists)') 

def dot_numexpr_based(new_v, val): 
    sq_dists = np.einsum('ij,ij->j',new_v, new_v) + val.dot(val) - 2*val.dot(new_v) 
    return ne.evaluate('sqrt(sq_dists)') 

計時 -

In [85]: # Inputs 
    ...: new_v = np.random.randint(0,9,(10,100000)) 
    ...: val = np.random.randint(0,9,(10)) 


In [86]: %timeit np.sqrt(np.sum(np.square(new_v-val.reshape(10,1)),axis=0)) 
    ...: %timeit einsum_based(new_v, val) 
    ...: %timeit dot_based(new_v, val) 
    ...: %timeit einsum_numexpr_based(new_v, val) 
    ...: %timeit dot_numexpr_based(new_v, val) 
    ...: 
100 loops, best of 3: 2.91 ms per loop 
100 loops, best of 3: 2.1 ms per loop 
100 loops, best of 3: 2.12 ms per loop 
100 loops, best of 3: 2.26 ms per loop 
100 loops, best of 3: 2.43 ms per loop 

In [87]: from numpy.linalg import norm 

# @wim's solution 
In [88]: %timeit norm(new_v.T-val, axis=1, ord=2) 
100 loops, best of 3: 5.88 ms per loop 
+0

這比OP的原始代碼imo更慢,更長,更不清晰。 – wim

+0

@wim如果您對性能感興趣,可以添加時間。關於「清楚」,好吧,如果我對「規範」一無所知,我想我可以對其他解決方案說同樣的話。 – Divakar

+0

我用'new_v = np.random.rand(10,1000)'和'val = np.random.rand(10)'。實際上,第一種使用2行的方法更快。我原本是在嘗試單線法。 – wim

1

你有什麼是正確的。 numpy.linalg有一個更簡單的方法:

from numpy.linalg import norm 
norm(new_v.T-val, axis=1, ord=2) 
+0

認爲通過調換二維數組,從性能角度講,你做錯了。如果你用'val'添加一個新的軸,然後沿'axis = 0'使用標準,你會看到改進:'norm(new_v-val [:,None],axis = 0,ord = 2)''。 – Divakar

+0

我跑了幾次,它似乎並不重要,可能是因爲它的轉置只是一個視圖,沒有在那裏複製。所以,我猜你很好。 – Divakar

+0

是的,我注意到將1-dim向量重塑爲2-dim列向量會稍快一些,而不是轉置矩陣。但是OP從未說過最高性能是目標,所以我更喜歡最具可讀性/ numpythonic的方法。 – wim

相關問題