Вычислить косинусное сходство между столбцом pandas Dataframe и списком, содержащим строковые значения - PullRequest
0 голосов
/ 24 февраля 2020

Я сейчас занимаюсь этим:

def word2vec(word):
    from collections import Counter
    from math import sqrt

    # count the characters in word
    cw = Counter(word)
    # precomputes a set of the different characters
    sw = set(cw)
    # precomputes the "length" of the word vector
    lw = sqrt(sum(c*c for c in cw.values()))

    # return a tuple
    return cw, sw, lw

def cosdis(v1, v2):
    # which characters are common to the two words?
    common = v1[1].intersection(v2[1])
    # by definition of cosine distance we have
    return sum(v1[0][ch]*v2[0][ch] for ch in common)/v1[2]/v2[2]

x= pd.DataFrame('id':['ABD','VWR', 'KPE', 'FFT'], Score:[30,23,25,21])
l1 = ['A', 'AB', 'KA', 'FF']
cosd={}

for i in l1:
    for index, j in x.iterrows():            
        cosd[i] = [j['id'], cosdis(word2vec(i), word2vec(j['id']))]        

Но я бы хотел более быстрый и оптимизированный способ сделать это. Я пытался использовать функцию pandas .apply.

1 Ответ

0 голосов
/ 24 февраля 2020

Вы можете использовать cosine_simility функцию из sklearn , которая является векторизованной версией вычисления косинусного подобия. Так что это будет намного быстрее, чем вычисление в a для l oop.

Предполагая, что у вас уже есть word2vec значений (с длиной 100) массивов l1 = ['ABD','VWR', 'KPE', 'FFT'] и l2 = ['A', 'AB', 'KA', 'FF'], так что вы будете иметь две матрицы размером [4 x 100]. Я буду случайным образом генерировать их, используя библиотеку numpy, поскольку у меня нет реализации word2vec:

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

l1 = np.random.rand(4, 100)
l2 = np.random.rand(4, 100)

print(cosine_similarity(l1, l2))

Вывод будет выглядеть следующим образом:

array([[0.75745762, 0.72183435, 0.74484246, 0.75241425],
       [0.68973308, 0.66498995, 0.63636494, 0.72047839],
       [0.79790214, 0.78010733, 0.77533   , 0.79282891],
       [0.76284434, 0.78694741, 0.76122869, 0.73728549]])

Чтобы проверить сходство между словом2ve c по индексу 0 в l1, равном 'ABD', и словом2ve c по индексу 1 в l2, равном 'AB', вы нужно проверить cosine_similarity(l1, l2)[0][1], что составляет 0.72183435

Кроме того, если мы проверим, что косинусное сходство l1 с самим собой, оно будет симметричным c, а диагональная матрица будет полна единиц .

print(cosine_similarity(l1, l1))
array([[1.        , 0.71591033, 0.83635512, 0.801628  ],
       [0.71591033, 1.        , 0.75567587, 0.73614333],
       [0.83635512, 0.75567587, 1.        , 0.82238456],
       [0.801628  , 0.73614333, 0.82238456, 1.        ]])

Редактировать:

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

word2vec_l1, word2vec_l2 = [], []

for i in x['id'].values:
  word2vec_l1.append(word2vec(i))

# This l2 is the l1 in your question which is ['A', 'AB', 'KA', 'FF']
for i in l2:
  word2vec_l2.append(word2vec(i))

word2vec_l1 = np.array(word2vec_l1)
word2vec_l2 = np.array(word2vec_l2)

Тогда вы можете вычислить косинусное сходство:

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