【问题标题】:Iterate pandas rows and compute cosine distance between rows迭代 pandas 行并计算行之间的余弦距离
【发布时间】:2017-08-03 09:47:12
【问题描述】:

我想计算熊猫数据框中每行之间的余弦距离。在计算距离之前,我只想选择大于 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 

【问题讨论】:

    标签: python pandas numpy vectorization trigonometry


    【解决方案1】:

    来自cosine docs 我们有以下信息 -

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

    uv 之间的余弦距离定义为

    其中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+在那里加速!

    【讨论】:

    • 这会计算“整个”2 个向量之间的距离,但不回答我的问题(例如,vector1 [0,1,45,0,0] 和 vector2 [4,11,2 ,0,0]。在这种情况下,程序只会计算 [1,45] 和 [11,2] 之间的余弦距离。)
    • @kitchenprinzessin 那么,您在问题中列出的代码一开始就不起作用?
    • 它永远运行,因为我有一个大数据框(1877 x 6516)。不过它适用于较小的数据框..
    • @kitchenprinzessin 好吧,我的意思是理论上你的代码会给你正确的结果,如果给出一些最小的样本数据,你在问题中的代码会给你正确的结果吗?
    • 是的,给定较小的数据帧,代码会产生正确的结果..
    猜你喜欢
    • 2016-11-29
    • 1970-01-01
    • 2017-01-13
    • 1970-01-01
    • 2014-08-21
    • 2017-09-15
    • 1970-01-01
    • 1970-01-01
    • 2018-03-21
    相关资源
    最近更新 更多