Обычный способ сделать это - преобразовать документы в векторы TF-IDF и затем вычислить косинусное сходство между ними. Любой учебник по поиску информации (IR) охватывает это. Смотрите особенно Введение в поиск информации , которая бесплатна и доступна онлайн.
Вычисление парных сходств
TF-IDF (и аналогичные преобразования текста) реализованы в пакетах Python Gensim и scikit-learn . В последнем пакете вычисление сходства косинусов так же просто, как
from sklearn.feature_extraction.text importTfidfVectorizer
documents =[open(f)for f in text_files]
tfidf =TfidfVectorizer().fit_transform(documents)# no need to normalize, since Vectorizer will return normalized tf-idf
pairwise_similarity = tfidf * tfidf.T
или, если документы представляют собой простые строки,
>>> corpus =["I'd like an apple",..."An apple a day keeps the doctor away",..."Never compare an apple to an orange",..."I prefer scikit-learn to Orange",..."The scikit-learn docs are Orange and Blue"]>>> vect =TfidfVectorizer(min_df=1, stop_words="english")>>> tfidf = vect.fit_transform(corpus)>>> pairwise_similarity = tfidf * tfidf.T
хотя у Генсима может быть больше вариантов для такого рода задач.
Допустим, мы хотим найти документ, наиболее похожий на итоговый документ, «Документы Scikit-Learn - оранжевые и синие». Этот документ имеет индекс 4 в corpus. Вы можете найти индекс наиболее похожего документа, взяв argmax этой строки, но сначала вам нужно замаскировать 1, которые представляют сходство каждого документа с самим собой . Вы можете сделать последнее через np.fill_diagonal(), а первое через np.nanargmax():
>>>import numpy as np
>>> arr = pairwise_similarity.toarray()>>> np.fill_diagonal(arr, np.nan)>>> input_doc ="The scikit-learn docs are Orange and Blue">>> input_idx = corpus.index(input_doc)>>> input_idx
4>>> result_idx = np.nanargmax(arr[input_idx])>>> corpus[result_idx]'I prefer scikit-learn to Orange'
Примечание: цель использования разреженной матрицы - сэкономить (значительное количество места) большой корпус и словарный запас. Вместо преобразования в массив NumPy вы можете сделать:
@larsmans Можете ли вы немного объяснить массив, если это возможно, как мне читать этот массив. Первые два столбца похожи между первыми двумя предложениями?
добавить точку с запятой
1
@ Нулевая гипотеза: в позиции (i, j) вы найдете показатель сходства между документом i и документом j. Таким образом, в позиции (0,2) находится значение сходства между первым документом и третьим (с использованием индексации на основе нуля), которое является тем же значением, которое вы найдете в (2,0), потому что косинусное сходство является коммутативным.
Фред Фу
1
Если бы мне нужно было усреднить все значения за пределами диагонали 1, было бы это разумным способом получить единую оценку того, насколько четыре документа похожи друг на друга? Если нет, есть ли лучший способ определения общего сходства между несколькими документами?
user301752
2
@ user301752: вы можете взять поэлементное среднее векторов tf-idf (как и k-means) X.mean(axis=0), а затем вычислить среднее / максимальное / медианное (∗) евклидово расстояние от этого среднего. (*) Выбери, что у тебя есть.
Фред Фу
1
@curious: я обновил пример кода до текущего API scikit-learn; Вы можете попробовать новый код.
Фред Фу
88
Идентичен @larsman, но с некоторой предварительной обработкой
import nltk, string
from sklearn.feature_extraction.text importTfidfVectorizer
nltk.download('punkt')# if necessary...
stemmer = nltk.stem.porter.PorterStemmer()
remove_punctuation_map = dict((ord(char),None)for char in string.punctuation)def stem_tokens(tokens):return[stemmer.stem(item)for item in tokens]'''remove punctuation, lowercase, stem'''def normalize(text):return stem_tokens(nltk.word_tokenize(text.lower().translate(remove_punctuation_map)))
vectorizer =TfidfVectorizer(tokenizer=normalize, stop_words='english')def cosine_sim(text1, text2):
tfidf = vectorizer.fit_transform([text1, text2])return((tfidf * tfidf.T).A)[0,1]print cosine_sim('a little bird','a little bird')print cosine_sim('a little bird','a little bird chirps')print cosine_sim('a little bird','a big dog barks')
@ Рено, действительно хороший и четкий ответ! У меня есть два сомнения: I) что такое [0,1], которое вы включаете после tfidf * tfidf.T) и II) Обратная частота документа формируется из всех статей или только из двух (учитывая, что у вас больше 2) ?
Economist_Ayahuasca
2
@AndresAzqueta [0,1] - это позиции в матрице сходства, поскольку два текстовых ввода создадут симметричную матрицу 2x2.
Филипп Бергстрем
1
@Renaud, спасибо за полный код. Для тех, кто столкнулся с ошибкой, запрашивающей nltk.download (), вы можете легко сделать nltk.download ('punkt'). Вам не нужно скачивать все.
1
@ Рено Я не понимаю более фундаментальную проблему. Какие строки текста должны fit, а какие transform?
Джон Строуд
@JohnStrood Я не понимаю вашего вопроса, извините, не могли бы вы переформулировать?
Renaud
45
Это старый вопрос, но я обнаружил, что это легко сделать с помощью Spacy . Как только документ прочитан, similarityможно использовать простой API , чтобы найти косинусное сходство между векторами документа.
Интересно, почему сходство между doc1 и doc2 составляет 0.999999954642, а не 1.0
JordanBelf
4
@JordanBelf Числа с плавающей запятой в большинстве языков немного расходятся, поскольку они не могут иметь неограниченную точность в цифровых представлениях. Например, операции с плавающей запятой или создание иррациональных чисел всегда имеют крошечные ошибки округления, которые затем умножаются. Это недостаток такого гибкого представления в масштабах.
скипилот
2
Какую функцию расстояния использует метод подобия в этом случае?
января
Если у вас возникли проблемы с поиском «en», запустите следующий pip install spacy && python -m spacy download en
Обычно косинусное сходство между двумя документами используется как мера сходства документов. В Java вы можете использовать Lucene (если ваша коллекция довольно большая) или LingPipe для этого. Основная концепция заключается в подсчете терминов в каждом документе и вычислении точечного произведения векторов терминов. Библиотеки предоставляют несколько улучшений по сравнению с этим общим подходом, например, использование обратных частот документа и вычисление векторов tf-idf. Если вы хотите что-то сделать с помощью copmlex, LingPipe также предоставляет методы для вычисления сходства LSA между документами, что дает лучшие результаты, чем косинусное сходство. Для Python вы можете использовать NLTK .
Обратите внимание, что здесь нет "сходства LSA". LSA - это метод уменьшения размерности векторного пространства (либо для ускорения, либо для моделирования тем, а не терминов). Те же самые метрики подобия, которые используются с BOW и tf-idf, могут использоваться с LSA (косинусное сходство, евклидово сходство, BM25,…).
Витико
16
Если вы ищете что-то очень точное, вам нужно использовать какой-то лучший инструмент, чем tf-idf. Универсальный кодировщик предложений является одним из наиболее точных, чтобы найти сходство между любыми двумя частями текста. Google предоставил предварительно обученные модели, которые вы можете использовать для своего собственного приложения без необходимости тренироваться с нуля. Во-первых, вам нужно установить тензор потока и тензор потока-хаб:
pip install tensorflow
pip install tensorflow_hub
Приведенный ниже код позволяет преобразовать любой текст в векторное представление фиксированной длины, а затем вы можете использовать точечное произведение, чтобы выяснить сходство между ними.
import tensorflow_hub as hub
module_url ="https://tfhub.dev/google/universal-sentence-encoder/1?tf-hub-format=compressed"# Import the Universal Sentence Encoder's TF Hub module
embed = hub.Module(module_url)# sample text
messages =[# Smartphones"My phone is not good.","Your cellphone looks great.",# Weather"Will it snow tomorrow?","Recently a lot of hurricanes have hit the US",# Food and health"An apple a day, keeps the doctors away","Eating strawberries is healthy",]
similarity_input_placeholder = tf.placeholder(tf.string, shape=(None))
similarity_message_encodings = embed(similarity_input_placeholder)with tf.Session()as session:
session.run(tf.global_variables_initializer())
session.run(tf.tables_initializer())
message_embeddings_ = session.run(similarity_message_encodings, feed_dict={similarity_input_placeholder: messages})
corr = np.inner(message_embeddings_, message_embeddings_)print(corr)
heatmap(messages, messages, corr)
и код для построения:
def heatmap(x_labels, y_labels, values):
fig, ax = plt.subplots()
im = ax.imshow(values)# We want to show all ticks...
ax.set_xticks(np.arange(len(x_labels)))
ax.set_yticks(np.arange(len(y_labels)))# ... and label them with the respective list entries
ax.set_xticklabels(x_labels)
ax.set_yticklabels(y_labels)# Rotate the tick labels and set their alignment.
plt.setp(ax.get_xticklabels(), rotation=45, ha="right", fontsize=10,
rotation_mode="anchor")# Loop over data dimensions and create text annotations.for i in range(len(y_labels)):for j in range(len(x_labels)):
text = ax.text(j, i,"%.2f"%values[i, j],
ha="center", va="center", color="w",
fontsize=6)
fig.tight_layout()
plt.show()
результат будет:
Как вы можете видеть, наибольшее сходство между текстами с самими собой, а затем с их близкими по смыслу текстами.
ВАЖНЫЙ : при первом запуске кода он будет медленным, потому что ему нужно загрузить модель. если вы хотите запретить повторную загрузку модели и использовать локальную модель, вам нужно создать папку для кэша и добавить ее в переменную среды, а затем после первого запуска использовать этот путь:
tf_hub_cache_dir = "universal_encoder_cached/"
os.environ["TFHUB_CACHE_DIR"] = tf_hub_cache_dir
# pointing to the folder inside cache dir, it will be unique on your system
module_url = tf_hub_cache_dir+"/d8fbeb5c580e50f975ef73e80bebba9654228449/"
embed = hub.Module(module_url)
привет, спасибо за этот пример, побуждающий меня попробовать TF - откуда должен появиться объект "np"?
Открытый Фуд Брокер
1
UPD хорошо, я установил numpy, matplotlib, а также системную привязку TK Python для сюжета, и она работает !!
Открытый продовольственный брокер
1
На всякий случай (извините за отсутствие разрывов строк): импортировать тензор потока в виде tf; импортировать в качестве тензорного потока как концентратор; импортировать matplotlib.pyplot в виде plt импортировать numpy как np
dinnouti
5
Вот небольшое приложение, чтобы вы начали ...
import difflib as dl
a = file('file').read()
b = file('file1').read()
sim = dl.get_close_matches
s = 0
wa = a.split()
wb = b.split()
for i in wa:
if sim(i, wb):
s += 1
n = float(s) / float(len(wa))
print '%d%% similarity' % int(n * 100)
Api использует дифференциальный последовательный Matcher? Если да, то просто функция в Python будет делать работу ____________________________________ из difflib импорта SequenceMatcher четкости isStringSimilar (а, б): соотношение = SequenceMatcher (None, а, б) .ratio) возвращает отношение (______________________________
Rudresh Ajgaonkar
2
Если вас больше интересует измерение семантического сходства двух фрагментов текста, я предлагаю взглянуть на этот проект gitlab . Вы можете запустить его в качестве сервера, также есть встроенная модель, которую вы можете легко использовать для измерения сходства двух фрагментов текста; хотя он в основном обучен измерению сходства двух предложений, вы все равно можете использовать его в своем случае. Он написан на Java, но вы можете запустить его как службу RESTful.
Другим вариантом также является DKPro Similarity - библиотека с различным алгоритмом измерения сходства текстов. Тем не менее, это также написано на Java.
пример кода:
// this similarity measure is defined in the dkpro.similarity.algorithms.lexical-asl package
// you need to add that to your .pom to make that example work
// there are some examples that should work out of the box in dkpro.similarity.example-gpl
TextSimilarityMeasure measure = new WordNGramJaccardMeasure(3); // Use word trigrams
String[] tokens1 = "This is a short example text .".split(" ");
String[] tokens2 = "A short example text could look like that .".split(" ");
double score = measure.getSimilarity(tokens1, tokens2);
System.out.println("Similarity: " + score);
Чтобы найти сходство предложений с очень меньшим набором данных и получить высокую точность, вы можете использовать ниже пакет python, который использует предварительно обученные модели BERT,
Я только что попробовал это, но это дает сходство каждого предложения с одним основным, но есть ли способ создать все обучающие данные в формате tear.txt как один класс и получить оценку того, насколько достоверно оно соответствует всем примерам ?
Гуру Теджа
1
да, можете, попробуйте .batch_predict (BatchFile, NumberOfPrediction), который выдаст результаты в виде Results.xls со столбцами ['Предложение', 'Предложение', 'Счёт']
Шанкар Ганеш Джаяраман
1
Для синтаксического сходства может быть 3 простых способа обнаружения сходства.
Word2Vec
Перчатка
Tfidf или countvectorizer
Для семантического сходства Можно использовать BERT Embedding и попробовать разные стратегии объединения слов, чтобы получить вложение документа, а затем применить косинусное сходство при встраивании документа.
Продвинутая методология может использовать BERT SCORE для получения сходства.
Ответы:
Обычный способ сделать это - преобразовать документы в векторы TF-IDF и затем вычислить косинусное сходство между ними. Любой учебник по поиску информации (IR) охватывает это. Смотрите особенно Введение в поиск информации , которая бесплатна и доступна онлайн.
Вычисление парных сходств
TF-IDF (и аналогичные преобразования текста) реализованы в пакетах Python Gensim и scikit-learn . В последнем пакете вычисление сходства косинусов так же просто, как
или, если документы представляют собой простые строки,
хотя у Генсима может быть больше вариантов для такого рода задач.
Смотрите также этот вопрос .
[Отказ от ответственности: я принимал участие в реализации TF-IDF scikit-learn.]
Интерпретация результатов
Сверху
pairwise_similarity
- скудная матрица Сципи, имеющая квадратную форму, с числом строк и столбцов, равным количеству документов в корпусе.Вы можете преобразовать разреженный массив в массив NumPy с помощью
.toarray()
или.A
:Допустим, мы хотим найти документ, наиболее похожий на итоговый документ, «Документы Scikit-Learn - оранжевые и синие». Этот документ имеет индекс 4 в
corpus
. Вы можете найти индекс наиболее похожего документа, взяв argmax этой строки, но сначала вам нужно замаскировать 1, которые представляют сходство каждого документа с самим собой . Вы можете сделать последнее черезnp.fill_diagonal()
, а первое черезnp.nanargmax()
:Примечание: цель использования разреженной матрицы - сэкономить (значительное количество места) большой корпус и словарный запас. Вместо преобразования в массив NumPy вы можете сделать:
источник
X.mean(axis=0)
, а затем вычислить среднее / максимальное / медианное (∗) евклидово расстояние от этого среднего. (*) Выбери, что у тебя есть.Идентичен @larsman, но с некоторой предварительной обработкой
источник
fit
, а какиеtransform
?Это старый вопрос, но я обнаружил, что это легко сделать с помощью Spacy . Как только документ прочитан,
similarity
можно использовать простой API , чтобы найти косинусное сходство между векторами документа.источник
Обычно косинусное сходство между двумя документами используется как мера сходства документов. В Java вы можете использовать Lucene (если ваша коллекция довольно большая) или LingPipe для этого. Основная концепция заключается в подсчете терминов в каждом документе и вычислении точечного произведения векторов терминов. Библиотеки предоставляют несколько улучшений по сравнению с этим общим подходом, например, использование обратных частот документа и вычисление векторов tf-idf. Если вы хотите что-то сделать с помощью copmlex, LingPipe также предоставляет методы для вычисления сходства LSA между документами, что дает лучшие результаты, чем косинусное сходство. Для Python вы можете использовать NLTK .
источник
Если вы ищете что-то очень точное, вам нужно использовать какой-то лучший инструмент, чем tf-idf. Универсальный кодировщик предложений является одним из наиболее точных, чтобы найти сходство между любыми двумя частями текста. Google предоставил предварительно обученные модели, которые вы можете использовать для своего собственного приложения без необходимости тренироваться с нуля. Во-первых, вам нужно установить тензор потока и тензор потока-хаб:
Приведенный ниже код позволяет преобразовать любой текст в векторное представление фиксированной длины, а затем вы можете использовать точечное произведение, чтобы выяснить сходство между ними.
и код для построения:
результат будет:
Как вы можете видеть, наибольшее сходство между текстами с самими собой, а затем с их близкими по смыслу текстами.
ВАЖНЫЙ : при первом запуске кода он будет медленным, потому что ему нужно загрузить модель. если вы хотите запретить повторную загрузку модели и использовать локальную модель, вам нужно создать папку для кэша и добавить ее в переменную среды, а затем после первого запуска использовать этот путь:
Дополнительная информация: https://tfhub.dev/google/universal-sentence-encoder/2.
источник
Вот небольшое приложение, чтобы вы начали ...
источник
Возможно, вы захотите попробовать этот онлайн-сервис для сходства документов косинуса http://www.scurtu.it/documentSdentifity.html
источник
Если вас больше интересует измерение семантического сходства двух фрагментов текста, я предлагаю взглянуть на этот проект gitlab . Вы можете запустить его в качестве сервера, также есть встроенная модель, которую вы можете легко использовать для измерения сходства двух фрагментов текста; хотя он в основном обучен измерению сходства двух предложений, вы все равно можете использовать его в своем случае. Он написан на Java, но вы можете запустить его как службу RESTful.
Другим вариантом также является DKPro Similarity - библиотека с различным алгоритмом измерения сходства текстов. Тем не менее, это также написано на Java.
пример кода:
источник
Чтобы найти сходство предложений с очень меньшим набором данных и получить высокую точность, вы можете использовать ниже пакет python, который использует предварительно обученные модели BERT,
источник
Для синтаксического сходства может быть 3 простых способа обнаружения сходства.
Для семантического сходства Можно использовать BERT Embedding и попробовать разные стратегии объединения слов, чтобы получить вложение документа, а затем применить косинусное сходство при встраивании документа.
Продвинутая методология может использовать BERT SCORE для получения сходства.
Ссылка на исследовательскую статью: https://arxiv.org/abs/1904.09675
источник