Python - 加速与scipy的余弦相似性

问题描述 投票:0回答:1

以下问题来自我以前做过的:Python - How to speed up cosine similarity with counting arrays

在使用提出的解决方案时,我面临着一个很大的复杂性问题,基本上,我的实现需要花费大量时间来构建余弦相似度矩阵。在我使用的代码下面:

import numpy as np
import pandas as pd
import networkx as nx
from scipy import spatial

def compute_other(user_1, user_2):
    uniq = list(set(user_1[0] + user_2[0]))

    duniq = {k:0 for k in uniq}    

    u1 = create_vector(duniq, list(user_1[0]))
    u2 = create_vector(duniq, list(user_2[0]))

    return 1 - spatial.distance.cosine(u1, u2)

# START
distances = spatial.distance.cdist(df[['ARTIST']], df[['ARTIST']], metric=compute_other)

idx_to_remove = np.triu_indices(len(distances))
distances[idx_to_remove] = 0

df_dist = pd.DataFrame(distances, index = df.index, columns = df.index)
edges = df_dist.stack().to_dict()
edges = {k: v for k, v in edges.items() if v > 0}

print('NET inference')
net = nx.Graph()
net.add_nodes_from(df.index)
net.add_edges_from(edges)     

我注意到的第一件事是我计算完整的矩阵并删除它的一半,所以只计算我需要的一半(这将是一个x2)会很酷。

那个df的结构:

ARTIST
"(75751, 75751, 75751, 75751, 75751, 75751, 75751, 75751, 75751, 75751, 75751, 75751, 75751, 75751, 15053)"
"(55852, 55852, 17727, 17727, 2182)"
"(11446, 11446, 11446, 11446, 11446, 11446, 11446, 11446)"
"(54795,)"
"(22873, 22873, 22873, 22873)"
"(5634, 5634)"
"(311, 18672)"
"(1740, 1740, 1740, 1740, 1746, 15048, 15048, 1740)"
"(1788, 1983, 1788, 1748, 723, 100744, 723, 226, 1583, 12188, 51325, 1748, 75401, 1171)"
"(59173, 59173)"
"(2673, 2673, 2673, 2673, 2673, 2673, 2673, 5634, 5634, 5634)"
"(2251, 4229, 14207, 1744, 16366, 1218)"
"(19703, 1171, 1171)"
"(12877,)"
"(1243, 8249, 2061, 1243, 13343, 9868, 574509, 892, 1080, 1243, 3868, 2061, 4655)"
"(1229,)"
"(3868, 60112, 11084)"
"(15869, 15869, 15869, 15869)"
"(4067, 4067, 4067, 4067, 4067, 4067)"
"(1171, 1171, 1171, 1171)"
"(1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1245, 1195, 1193, 1193, 1193, 1193, 1193, 1193)"
"(723, 723)"  

这个dataset已经完成,可以和我发布的代码一起使用。只需将其作为普通的csv与pandas一起阅读并应用该功能:

import ast
import pandas as pd

df = pd.read_csv('Stack.csv')
df['ARTIST'] = df['ARTIST'].apply(lambda x : ast.literal_eval(x))

这段代码几乎在166中执行。我在我的8核处理器上并行执行8个进程,每个进程在不同的数据集上计算相同的函数。老实说,我不知道这是否已经是最优化的版本,但是,如前所述,删除一半的计算也非常有用(从16683)。

编辑:创建矢量函数下面:

def create_vector(duniq, l):
    dx = duniq.copy()
    dx.update(Counter(l)) # Count the values
    return list(dx.values()) # Return a list
python pandas scipy
1个回答
1
投票

我试图修改它,但是我在两行上得到编译错误:u1 = create_vector(duniq,list(user_1 [0]))u2 = create_vector(duniq,list(user_2 [0]))

是create_vector()你建立的def,但没有发布?

我怀疑在你身上使用掩码df可能会通过删除你正在做的距离[idx_to_remove] = 0来改善性能,并且应该减少“edges = {k:v for k,v in edges.items”中的迭代次数( )如果v> 0}“

如果你可以发布create_vector()来自哪里,或def本身,我想测试一个掩码。这是一个有趣的问题。

嗨@Guido。花了这么长时间道歉,但这已经是难以破解的!在尝试了一些不同的东西(花了更长的时间)后,我想出了以下代码来代替你的create_vector()和compute_other()函数:

def compute_other2(user_1, user_2):
    uniq = set(user_1[0] + user_2[0]) #create list of unique list of items in user _1 and user_2   
    u1 = [user_1[0].count(ui) for ui in uniq]
    u2 = [user_2[0].count(ui) for ui in uniq]
    return 1 - spatial.distance.cosine(u1, u2)

我的性能提升了20%,低于我的预期,但还有一些东西。注意:我仍然使用“spatial.distance.cdist”运行代码。我确实看到你通过切换到“spatial.distance.pdist”获得了50%。我不确定你是如何使用它的(我怀疑是矢量数学)超出了我的想法。也许你可以在spatial.distance.pdist中使用这个新的compute_other()函数并获得更多。

附:如果你试试这个,请验证结果。我检查了我的原始代码,看起来对我来说是正确的。

© www.soinside.com 2019 - 2024. All rights reserved.