迭代pandas行并计算行

时间:2017-03-13 11:30:47

标签: python pandas numpy vectorization cosine

我想计算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 

1 个答案:

答案 0 :(得分:1)

cosine docs我们有以下信息 -

scipy.spatial.distance.cosine(u,v):计算1-D数组之间的余弦距离。

uv之间的余弦距离定义为

enter image description here

其中u⋅vuv的点积。

使用上面的公式,我们将使用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+ 加速!