[英]Distance calculation between rows in Pandas Dataframe using a distance matrix
我有以下Pandas DataFrame:
In [31]:
import pandas as pd
sample = pd.DataFrame({'Sym1': ['a','a','a','d'],'Sym2':['a','c','b','b'],'Sym3':['a','c','b','d'],'Sym4':['b','b','b','a']},index=['Item1','Item2','Item3','Item4'])
In [32]: print(sample)
Out [32]:
Sym1 Sym2 Sym3 Sym4
Item1 a a a b
Item2 a c c b
Item3 a b b b
Item4 d b d a
我想找到一種優雅的方法來根據這個距離矩陣得到每個Item
之間的距離:
In [34]:
DistMatrix = pd.DataFrame({'a': [0,0,0.67,1.34],'b':[0,0,0,0.67],'c':[0.67,0,0,0],'d':[1.34,0.67,0,0]},index=['a','b','c','d'])
print(DistMatrix)
Out[34]:
a b c d
a 0.00 0.00 0.67 1.34
b 0.00 0.00 0.00 0.67
c 0.67 0.00 0.00 0.00
d 1.34 0.67 0.00 0.00
例如,比較Item1
和Item2
將比較aaab
- > accb
- 使用距離矩陣,這將是0+0.67+0.67+0=1.34
理想輸出:
Item1 Item2 Item3 Item4
Item1 0 1.34 0 2.68
Item2 1.34 0 0 1.34
Item3 0 0 0 2.01
Item4 2.68 1.34 2.01 0
這是一個老問題,但有一個Scipy函數可以做到這一點:
from scipy.spatial.distance import pdist, squareform
distances = pdist(sample.values, metric='euclidean')
dist_matrix = squareform(distances)
pdist
在Numpy矩陣上運行, DataFrame.values
是數據幀的底層Numpy NDarray表示。 metric
參數允許您選擇幾個內置距離度量中的一個,或者您可以傳入任何二進制函數以使用自定義距離。 這是非常強大的,根據我的經驗,非常快。 結果是一個“平面”數組,它只包含距離矩陣的上三角形(因為它是對稱的),不包括對角線(因為它總是為0)。 squareform
然后將這種扁平形式轉換為完整矩陣。
文檔有更多信息,包括許多內置距離函數的數學綱要。
對於大數據,我發現了一種快速的方法。 假設您的數據已經是np.array格式,名為a。
from sklearn.metrics.pairwise import euclidean_distances
dist = euclidean_distances(a, a)
以下是比較兩種方法所需時間的實驗:
a = np.random.rand(1000,1000)
import time
time1 = time.time()
distances = pdist(a, metric='euclidean')
dist_matrix = squareform(distances)
time2 = time.time()
time2 - time1 #0.3639109134674072
time1 = time.time()
dist = euclidean_distances(a, a)
time2 = time.time()
time2-time1 #0.08735871315002441
這是根據需要做兩倍的工作,但技術上也適用於非對稱距離矩陣(不管是什么意思)
pd.DataFrame ( { idx1: { idx2:sum( DistMatrix[ x ][ y ]
for (x, y) in zip( row1, row2 ) )
for (idx2, row2) in sample.iterrows( ) }
for (idx1, row1 ) in sample.iterrows( ) } )
您可以通過將其分成幾部分來使其更具可讀性:
# a helper function to compute distance of two items
dist = lambda xs, ys: sum( DistMatrix[ x ][ y ] for ( x, y ) in zip( xs, ys ) )
# a second helper function to compute distances from a given item
xdist = lambda x: { idx: dist( x, y ) for (idx, y) in sample.iterrows( ) }
# the pairwise distance matrix
pd.DataFrame( { idx: xdist( x ) for ( idx, x ) in sample.iterrows( ) } )
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.