Меняется ли евклидово расстояние, когда строки «удваиваются»? - PullRequest
1 голос
/ 17 апреля 2020

Задача Я пытаюсь ответить на этот вопрос: рассмотрим два документа A и B, евклидово расстояние которых равно d, а косинусное сходство равно c (без нормализации, кроме необработанных терминов частот). Если мы создадим новый документ A ', добавив A к себе, а другой документ B', добавив B к себе, то:

a. Каково евклидово расстояние между A 'и B' (с использованием частоты необработанного термина) ?

Мое решение

doc1 = "the quicker brown dogs easily jumps over the lazy dogs" 
doc2 = "the quicker dogs pose a serious problem for lazy dogs"

def calc_term_frequency(doc : list):

    dic = {}
    for word in doc.split():
        if word in dic:
            dic[word] = dic[word] + 1
        else:
            dic[word]= 1

    for word, frequency in dic.items():
       dic[word]= frequency / len(doc.split())

    return dic

tfs_doc1 = calc_term_frequency(doc1)
tfs_doc2 = calc_term_frequency(doc2)
print(tfs_doc1)

Выводит tfs_doc1 как: {'the': 0.2, 'быстрее': 0.1, 'коричневый': 0.1, 'собаки': 0,2, «легко»: 0,1, «прыжки»: 0,1, «над»: 0,1, «ленивый»: 0,1} Кажется, что это работает на это следует. Затем я продолжаю вычислять евклидово расстояние, сначала между doc1 и doc1, а затем doc1 и doc2, как показано ниже.

import math
math.sqrt(sum((tfs_doc1.get(k, 0) - tfs_doc1.get(k, 0))**2 for k in set(tfs_doc1.keys()).union(set(tfs_doc1.keys())))) # output: 0
math.sqrt(sum((tfs_doc1.get(k, 0) - tfs_doc2.get(k, 0))**2 for k in set(tfs_doc1.keys()).union(set(tfs_doc2.keys())))) # output: 0.316227766016838

Это дает мне 0,316227766016838. Когда я пытаюсь проверить, что это правильно, используя sklearn, как показано ниже:

from sklearn.feature_extraction.text import CountVectorizer
from sklearn.metrics.pairwise import euclidean_distances

corpus_vect = CountVectorizer().fit_transform(corpus).todense() 

print(euclidean_distances(corpus_vect[0], corpus_vect[0])) # output: 0
print(euclidean_distances(corpus_vect[0], corpus_vect[1] )) # output: 3.

, я получаю вывод [[0.]] [[3.]], который переводится в round (, 1) моего "ручного" результата.

Проблема: , когда я пытаюсь ответить на начальные вопросы и «удвоить» строки, например,

doc1 = "the quicker brown dogs easily jumps over the lazy dogs the quicker brown dogs easily jumps over the lazy dogs" 
doc2 = "the quicker dogs pose a serious problem for lazy dogs the quicker dogs pose a serious problem for lazy dogs"

Я получаю тот же вывод для ручной техники ( 0.316227766016838) но [[0.]] [[6.]] при использовании «метода sklearn» / Vectorizer. Таким образом, при использовании одного метода ЭД остается неизменным, а при использовании другого он удваивается!

Какое правильное решение и в чем причина разницы? Действительно застрял здесь. Заранее спасибо.

1 Ответ

1 голос
/ 17 апреля 2020

Когда вы удвоите строку, частота всех терминов (включая необработанные) будет дублироваться. Следовательно, если до дублирования у вас есть частотный вектор (a1, a2, ..., ad) и (b1, b2, ..., bd) для документов A и B, соответственно, евклидово диастанс будет sqrt((a1-b1)^2 + (a2-b2)^2 + ... + (ad - bd)^2). Теперь, после дублирования у нас есть (2 * a1, 2 * a2, ..., 2 * ad) и (2 * b1,2 * b2, ...,2 * bd), а расстояние равно:

dist(A', B') = sqrt((2 * a1- 2 * b1)^2 + (2 * a2 - 2 *b2)^2 + ... + (2 * ad - 2 * bd)^2) = 
2 * sqrt((a1-b1)^2 + (a2-b2)^2 + ... + (ad - bd)^2) = 2 * dist(A,B)

Осторожно, в ручном решении вы делите частоту на длину документа, и это предотвращает дублирование термина частота.

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