#python #arrays #list #scipy
#python #массивы #Список #scipy
Вопрос:
Мне нужно вычислить функцию косинусного подобия для очень большого набора. Этот набор представляет пользователей и каждого пользователя в виде массива идентификаторов объектов. Пример ниже:
user_1 = [1,4,6,100,3,1]
user_2 = [4,7,8,3,3,2,200,9,100]
Если я правильно понимаю, для вычисления подобия косинуса мне нужно сначала создать подсчитывающие массивы, чтобы иметь общее представление для каждого из них. Затем мне нужно вычислить функцию подобия косинуса. Для подсчета массивов я имею в виду следующее:
#user_1 array
# 1,2,3,4,5,6,[7-99],100,[101-200]
user_1_counting_array = [2,0,1,1,0,1,.......,1,.........]
user_2_counting_array = [0,1,2,1,0,0,1,1,1,.,1,.......,1]
(В данном случае точки представляют нули)
после того, как я получу это общее представление, я использую функцию косинусного подобия из sklearn.
from scipy import spatial
s = 1 - spatial.distance.cosine(user_1_counting_array, user_2_counting_array)
Проблема в том, что когда я на самом деле запускаю код, все происходит чрезвычайно медленно, и у меня более 1 МЛН пользователей. Я понимаю, что комбинации будет много, но я думаю, что то, как я создаю общее представление, создает очень большое узкое место.
Для полноты картины ниже представлена моя реализация:
from collections import Counter
from scipy import spatial
def fill_array(array, counter):
for c in counter:
array[c] = counter[c]
return array
user_1 = [1,4,6,100,3,1]
user_2 = [4,7,8,3,3,2,200,9,100]
user_1_c = Counter(user_1)
user_2_c = Counter(user_2)
if max(user_1_c) > max(user_2_c):
max_a = max(user_1_c) 1
else:
max_a = max(user_2_c) 1
user_1_c_array = [0]*max_a
user_2_c_array = [0]*max_a
fill_array(user_1_c_array, user_1_c)
fill_array(user_2_c_array, user_2_c)
result = 1 - spatial.distance.cosine(user_1_c_array, user_2_c_array)
Комментарии:
1. Я предполагаю, что вы делаете это для графиков (например, друзей / соединений). В этом случае вам не нужно использовать косинусное подобие для всех перед max_index . Вам нужно использовать только вектор, который содержит все элементы, которые существуют хотя бы в одном из двух списков .
2. Вы правы, но с точки зрения вычислений у меня такое чувство, что для создания этих векторов требуется гораздо больше вычислений. Вы так не думаете? @RockyLi
3. На самом деле это намного меньше, поскольку вы перебираете огромное количество пустых данных. Это также быстрее, когда вы используете хэш (set, dictionary).
Ответ №1:
Вот как вы можете получить свои короткие и лаконичные векторы косинусного подобия, не перебирая более миллиона записей:
user_1 = [1,4,6,100,3,1]
user_2 = [4,7,8,3,3,2,200,9,100]
# Create a list of unique elements
uniq = list(set(user_1 user_2))
# Map all unique entrees in user_1 and user_2
duniq = {k:0 for k in uniq}
def create_vector(duniq, l):
dx = duniq.copy()
dx.update(Counter(l)) # Count the values
return list(dx.values()) # Return a list
u1 = create_vector(duniq, user_1)
u2 = create_vector(duniq, user_2)
# u1, u2:
u1 = [2, 0, 1, 1, 1, 0, 0, 0, 0, 1]
u2 = [0, 1, 2, 1, 0, 1, 1, 1, 1, 1]
Затем вы можете передать эти 2 вектора в spatial.distance.cosine