Python - ускорить сходство косинусов со Сципионом - PullRequest
0 голосов
/ 23 марта 2019

следующий вопрос возникает из предыдущего, который я сделал ранее: Python - Как ускорить сходство косинусов с подсчетом массивов

Я сталкиваюсь с большой сложностью при использовании предложенного решения, в основном, моя реализация занимает много времени для построения матрицы косинусного сходства. Ниже код, который я использую:

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)     

Первое, что я замечаю, это то, что я вычисляю полную матрицу и удаляю половину ее, поэтому было бы здорово вычислить только половину Мне нужно (это будет х2).

Это структура 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)"  

Этот набор данных завершен и может использоваться с кодом, который я разместил. Просто прочитайте его как обычный csv с пандами и примените эту функцию:

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-ядерном процессоре, каждый процесс вычисляет одну и ту же функцию в своем наборе данных. Честно говоря, я не знаю, является ли это уже самой оптимизированной версией, однако, удаление половины вычислений, как я объяснял ранее, было бы действительно полезным (переход от 166 к 83).

РЕДАКТИРОВАТЬ: ниже функции create_vector:

def create_vector(duniq, l):
    dx = duniq.copy()
    dx.update(Counter(l)) # Count the values
    return list(dx.values()) # Return a list

1 Ответ

1 голос
/ 23 марта 2019

Я пытался возиться с этим, однако я получаю ошибку компиляции в двух строках: u1 = create_vector (duniq, list (user_1 [0])) u2 = create_vector (duniq, list (user_2 [0]))

является ли create_vector () определением, которое вы создали, но не публиковали?

Я подозреваю, что использование маски на вашем df, вероятно, улучшит производительность, удалив перезапись, которую вы выполняете с расстояниями [idx_to_remove]= 0 и должно уменьшить количество итераций в "dge = {k: v для k, v вdge.items (), если v> 0} "

Если вы можете опубликовать, откуда исходит create_vector ()или само определение, я хотел бы проверить маску.Это интересная проблема.

Привет, Гвидо.Извините за то, что так долго, но это был крепкий орешек!Попробовав несколько разных вещей (это заняло еще больше времени), я пришел к следующему, чтобы использовать вместо ваших функций 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% производительностиулучшение, меньше, чем я надеялся, но кое-что.Примечание. Я по-прежнему выполняю ваш код с «pace.distance.cdist ».Я видел, что вы получили 50%, переключившись на «atial.distance.pdist ».Я не уверен, как вы использовали это и (что я подозреваю, это векторная математика) за пределами моего понимания.Возможно, вы можете использовать эту новую функцию compute_other () с пространственным.distance.pdist и получить немного больше.

PS Если вы попробуете это, проверьте результаты.Я проверил мой по вашему исходному коду, и он мне кажется правильным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...