我想计算pandas数据帧中每行之间的余弦距离。在计算距离之前,我想仅选择向量中的元素> 0和相交(两行中都有值)。例如,row1 [0,1,45,0,0]和row2 [4,11,2,0,0]。在这种情况下,程序只计算[1,45]和[11,2]之间的余弦距离。这是我的脚本,但这需要很长时间才能完成。任何有关简化脚本和减少处理时间的帮助都表示赞赏。
data = df.values
m, k = data.shape
dist = np.zeros((m, m))
for i in range(m):
for j in range(i,m):
if i!=j:
vec1 = data[i,:]
vec2 = data[j,:]
pairs = [(x, y) for (x, y) in zip(vec1, vec2) if x > 0 and y > 0]
if pairs:
sub_list_1, sub_list_2 = map(list, zip(*pairs))
dist[i][j] = dist[j][i]=cosine(sub_list_1, sub_list_2)
else:
dist[i][j]= dist[j][i] =1
else:
dist[i][j]=0
答案 0 :(得分:1)
从cosine docs
我们有以下信息 -
scipy.spatial.distance.cosine(u,v):计算1-D数组之间的余弦距离。
u
和v
之间的余弦距离定义为
其中u⋅v
是u
和v
的点积。
使用上面的公式,我们将使用NumPy's broadcasting
使用一个矢量化解决方案,就像这样 -
def self_cosine_vectorized(a):
dots = a.dot(a.T)
sqrt_sums = np.sqrt((a**2).sum(1))
cosine_dists = 1 - (dots/sqrt_sums)/sqrt_sums[:,None]
np.fill_diagonal(cosine_dists,0)
return cosine_dists
因此,要获得dist
-
dist = self_cosine_vectorized(df.values)
运行时测试和验证
原创方法:
def original_app(data):
m, k = data.shape
dist = np.zeros((m, m))
for i in range(m):
for j in range(m):
if i!=j:
vec1 = data[i,:]
vec2 = data[j,:]
pairs = [(x, y) for (x, y) in zip(vec1, vec2) if x > 0 and y > 0]
if pairs:
sub_list_1, sub_list_2 = map(list, zip(*pairs))
dist[i][j] = cosine(sub_list_1, sub_list_2)
else:
dist[i][j]
else:
dist[i][j]=0
return dist
计时和验证 -
In [203]: data = np.random.rand(100,100)
In [204]: np.allclose(original_app(data), self_cosine_vectorized(data))
Out[204]: True
In [205]: %timeit original_app(data)
1 loops, best of 3: 813 ms per loop
In [206]: %timeit self_cosine_vectorized(data)
10000 loops, best of 3: 101 µs per loop
In [208]: 813000.0/101
Out[208]: 8049.504950495049
疯狂 8000x+
加速!