Вопрос:

Косинусное сходство для очень большого набора данных

python numpy dataframe cosine-similarity

642 просмотра

2 ответа

37002 Репутация автора

У меня возникли проблемы с вычислением косинусного сходства между большим списком 100-мерных векторов. Когда я использую from sklearn.metrics.pairwise import cosine_similarity, я получаю MemoryErrorна моей машине 16 ГБ. Каждый массив отлично умещается в моей памяти, но я получаю MemoryErrorво время np.dot()внутреннего вызова

Вот мой вариант использования и как я в настоящее время решаю его.

Вот мой родительский вектор 100-размерности, который мне нужно сравнить с другими 500 000 различных векторов того же измерения (т.е. 100)

parent_vector = [1, 2, 3, 4 ..., 100]

Вот мои дочерние векторы (с некоторыми вымышленными случайными числами для этого примера)

child_vector_1 = [2, 3, 4, ....., 101]
child_vector_2 = [3, 4, 5, ....., 102]
child_vector_3 = [4, 5, 6, ....., 103]
.......
.......
child_vector_500000 = [3, 4, 5, ....., 103]

Моя конечная цель состоит в том, чтобы получить топ-N дочерних векторов (с их именами, такими как child_vector_1и соответствующий им показатель косинуса), которые имеют очень высокое сходство косинусов с родительским вектором.

Мой текущий подход (который я знаю, неэффективен и требует много памяти):

Шаг 1: Создайте супер-фрейм данных следующей формы

parent_vector         1,    2,    3, .....,    100   
child_vector_1        2,    3,    4, .....,    101   
child_vector_2        3,    4,    5, .....,    102   
child_vector_3        4,    5,    6, .....,    103   
......................................   
child_vector_500000   3,    4,    5, .....,    103

Шаг 2: Используйте

from sklearn.metrics.pairwise import cosine_similarity
cosine_similarity(df)

чтобы получить попарно подобие косинуса между всеми векторами (показано в приведенном выше кадре данных)

Шаг 3: Составьте список кортежей для хранения keyтаких, как child_vector_1и значения, таких как косинусное сходство, для всех таких комбинаций.

Шаг 4: Получить top-N использование sort()списка - так, чтобы я получил имя дочернего вектора, а также его косинус сходство с родительским вектором.

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

Любая помощь будет высоко оценен.

Автор: sgokhales Источник Размещён: 20.12.2018 08:18

Ответы (2)


0 плюса

1 Репутация автора

даже если ваш (500000, 100) массив (родитель и его дочерние элементы) помещается в память, любая попарная метрика на нем не будет. Причиной этого является то, что попарно метрика, как следует из названия, вычисляет расстояние для любых двух детей. Чтобы сохранить эти расстояния, вам понадобится массив с плавающей точкой (500 000 500 000), который, если мои вычисления верны, займет около 100 ГБ памяти.

К счастью, есть простое решение для вашей проблемы. Если я вас правильно понимаю, вы хотите иметь только расстояние между ребенком и родителями, что приведет к вектору длины 500000, который легко сохранится в памяти.

Для этого вам просто нужно предоставить второй аргумент для cosine_simility, содержащий только parent_vector

import pandas as pd
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity

df = pd.DataFrame(np.random.rand(500000,100)) 
df['distances'] = cosine_similarity(df, df.iloc[0:1]) # Here I assume that the parent vector is stored as the first row in the dataframe, but you could also store it separately

n = 10 # or however many you want
n_largest = df['distances'].nlargest(n + 1) # this contains the parent itself as the most similar entry, hence n+1 to get n children

надеюсь, что решит ваш вопрос.

Автор: Sebastian Dick Размещён: 20.12.2018 10:59

0 плюса

1 Репутация автора

Это решение безумно быстро

child_vectors = np.array(child_vector_1, child_vector_2, ....., child_vector_500000)
input_norm = parent_vector / np.linalg.norm(parent_vector, axis=-1)[:, np.newaxis]
embed_norm =  child_vectors/ np.linalg.norm(child_vectors, axis=-1)[:, np.newaxis]
cosine_similarities = np.sort(np.round(np.dot(input_norm, embed_norm.T), 3)[0])[::-1]
paiswise_distances = 1 - cosine_similarities
Автор: Vamshi Размещён: 11.08.2019 08:20
Вопросы из категории :
32x32