Scipy Cosine Сходство очень медленно, используя панды Dataframes - PullRequest
0 голосов
/ 22 мая 2018

Несколько дней назад я начал изучать Python, занимаясь проектом.У меня есть два кадра данных, которые я подготовил из своих данных, которые представляют собой пользовательский и элемент данных.Пользователь DF имеет 17 000 различных пользователей, а Item DF имеет 1500 альбомов.Я использую коллаборативную фильтрацию, чтобы получить косинусное сходство между двумя кадрами данных, как показано ниже

from scipy.spatial.distance import cosine
for i in range(0,len(user_normalized.index)-1):
 for j in range(0,len(item_matrix.index)-1):
  item_matrix_cpy.at[j, 'cosine'] = 1 -cosine(item_matrix_same_shape.iloc[j], user_normalized.iloc[i])  

Я заметил, что моя логика циклического выполнения работает очень медленно и работает до бесконечности.Я проверил логику для нескольких пользователей (<10) и заметил, что вычисление косинуса занимает больше времени (~ 12 с).Но когда я попытался запустить одну и ту же косинусную логику для всех пользователей (т. Е. 17 КБ), выполнение запроса длилось вечно.Ребята, можете ли вы помочь мне здесь? </p>

Ответы [ 2 ]

0 голосов
/ 23 мая 2018

Вы можете использовать sklearn.metrics.pairwise.cosine_similarity, который принимает 2 матрицы в качестве входных данных.Этот метод гораздо более эффективен, чем выполнение вычислений для каждой пары в отдельности.

from sklearn.metrics.pairwise import cosine_similarity
cosine_similarity(
    item_matrix_same_shape.values,
    user_normalized.values
)

Вот реализация sklearn строка 888:

  • Используется толькоОперация с пустой матрицей, без питона для цикла
  • Она вычисляет норму только один раз для каждого семпла (пользователя, альбома) с помощью функции normalize.С вашим кодом норма каждого вектора альбома вычисляется 17K раз!
0 голосов
/ 22 мая 2018

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

timeit.timeit('cosine_similarity(x,y)',setup='from sklearn.metrics.pairwise import cosine_similarity; import numpy as np; x,y = np.random.random(100),np.random.random(100)',number=20000)
4.5380048290098784

timeit.timeit('cosine(x,y)',setup='from scipy.spatial.distance import cosine; import numpy as np; x,y = np.random.random(100),np.random.random(100)',number=20000)
0.6468068649992347

Так что кажется, что scipy's косинус превосходит значение sklearn, поэтому мы, вероятно, выиграли 'Выгода от переключения реализации ... Продолжается.

Если вы хотите выполнить попарно-косинусное сходство для матрицы из 17 тыс. записей, то это примерно равно 17k^2 оценкам == 289,000,000, что ужемного, и особенно, если ваши векторы также являются многомерными.

Давайте посмотрим, как быстро можно получить косинусное сходство на thousandth ваших входных данных, поэтому 289,000 оценки.

timeit.timeit('cosine(x,y)',setup='from scipy.spatial.distance import cosine; import numpy as np; x,y = np.random.random(100),np.random.random(100)',number=int((17000**2)/1000))
9.857225538988132

Это займет около 10 секунд.Поскольку это число растет линейно с ростом количества случаев ... Вы можете ожидать, что потратите 10000 секунд или чуть менее 3 часов на выполнение около 300 миллионов операций по подобию косинусов (в моем случае для векторов длины 100).

Таким образом, вычисление подобия косинуса должно занять определенное время.Одним из способов потенциального улучшения вашего кода является сохранение косинусных сходств в новом кадре данных или новой серии, а затем подключение его к исходному кадру данных с использованием индекса, в отличие от добавления к кадру данных на каждой итерации цикла.используя метод at (возможно, очень медленный).

Если все это имеет смысл, тогда ваша вычислительная нагрузка достаточно высока, так что ноутбук начинает чувствовать себя слабым.Что вы делаете дальше, зависит от вашего варианта использования - нужно ли это делать один раз?Просто запустите его и забудьте об этом.

Нужно делать это время от времени, но не слишком часто?Распараллелите вашу реализацию (если у вас есть четыре ядра, используйте все сразу), используя модуль multiprocessing в python (важно не использовать multithreading, в этом случае он не будет работать).

Нужно часто это запускать?Вам может понадобиться больше оборудования или посмотреть на решения для облачных вычислений - вы будете удивлены, насколько доступной может быть правильно управляемая облачная вычислительная установка.

...