2012-01-17 3 views
126

Я ищу работу над проектом NLP на любом языке (хотя Python будет моим предпочтением).Сходство между двумя текстовыми документами

Я хочу написать программу, которая возьмет два документа и определит, насколько они похожи.

Поскольку я довольно новичок в этом, и быстрый поиск в Google не указывает мне слишком много. Знаете ли вы о каких-либо ссылках (веб-сайтах, учебниках, журнальных статьях), которые охватывают этот вопрос и будут полезны для меня?

Благодаря

+1

Аналогичный вопрос здесь http://stackoverflow.com/questions/101569/algorithm-to-detect-similar-documents-in-python-script witch some nice answer –

ответ

188

Общий способ сделать это заключается в преобразовании документов в ТФ-IDF векторов, то вычислить косинуса сходство между ними. Любой учебник по поиску информации (IR) охватывает это. См. Introduction to Information Retrieval, который является бесплатным и доступен онлайн.

Tf-idf (и аналогичные текстовые преобразования) реализованы в пакетах Python Gensim и scikit-learn. В последнем пакете, вычисление косинуса сходства является столь же легко, как

from sklearn.feature_extraction.text import TfidfVectorizer 

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 

или, если документы являются простыми строками,

>>> vect = TfidfVectorizer(min_df=1) 
>>> tfidf = vect.fit_transform(["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"]) 
>>> (tfidf * tfidf.T).A 
array([[ 1.  , 0.25082859, 0.39482963, 0.  ], 
     [ 0.25082859, 1.  , 0.22057609, 0.  ], 
     [ 0.39482963, 0.22057609, 1.  , 0.26264139], 
     [ 0.  , 0.  , 0.26264139, 1.  ]]) 

хотя Gensim может иметь больше возможностей для такого рода задач.

См. Также this question.

[Отказ от ответственности:. Я был вовлечен в scikit учиться Tf-IDF реализации]

+1

@larsmans Можете ли вы объяснить массив немного, если это возможно, как я должен читать этот массив. Первые два столбца являются сходством между двумя первыми предложениями? –

+1

@ Null-Hypothesis: в позиции (i, j) вы найдете оценку подобия между документом i и документом j. Таким образом, в позиции (0,2) есть значение подобия между первым и третьим (с использованием индексации на основе нуля), которое является тем же значением, которое вы находите в (2,0), потому что сходство косинусов является коммутативным. –

+1

Если бы мне пришлось усреднять все значения за пределами диагонали 1, это был бы хороший способ получить единую оценку того, насколько похожи четыре документа друг другу? Если нет, есть ли лучший способ определить общее сходство между несколькими документами? – user301752

16

Вообще косинус сходство между двумя документами используется в качестве меры подобия документов. В Java вы можете использовать Lucene (если ваша коллекция довольно большая) или LingPipe для этого. Основная концепция заключалась бы в подсчете терминов в каждом документе и вычислении точечного произведения термина векторов. Библиотеки предоставляют несколько улучшений в отношении этого общего подхода, например. используя частоты обратного документа и вычисляя векторы tf-idf. Если вы хотите что-то сделать copmlex, LingPipe также предоставляет методы для расчета сходства LSA между документами, которые дают лучшие результаты, чем сходство с косинусом. Для Python вы можете использовать NLTK.

+0

Обратите внимание, что нет «сходства LSA». LSA - метод уменьшения размерности векторного пространства (либо для ускорения процесса, либо для моделирования тем, а не для терминов). Аналогичные показатели сходства, которые используются с BOW и tf-idf, могут использоваться с LSA (сходство косинусов, эвклидовое сходство, BM25, ...). – Witiko

3

Вот небольшое приложение, чтобы вы начали ...

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) 
+2

difflib очень медленный, если вы собираетесь работать с большим количеством документов. –

1

Вы можете попробовать этот сервис онлайн косинус документа подобия http://www.scurtu.it/documentSimilarity.html

import urllib,urllib2 
import json 
API_URL="http://www.scurtu.it/apis/documentSimilarity" 
inputDict={} 
inputDict['doc1']='Document with some text' 
inputDict['doc2']='Other document with some text' 
params = urllib.urlencode(inputDict)  
f = urllib2.urlopen(API_URL, params) 
response= f.read() 
responseObject=json.loads(response) 
print responseObject 
+0

- это Api с использованием дифференциального последовательного совпадения? Если да, то просто функция в Python будет выполнять работу ____________________________________ из difflib импорта SequenceMatcher Защиту isStringSimilar (а, б): отношение = SequenceMatcher (None, а, б) .ratio() обратный коэффициент ______________________________ –

60

Идентичный @larsman, но с некоторыми предварительная обработка

import nltk, string 
from sklearn.feature_extraction.text import TfidfVectorizer 

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') 
+0

@ Рено, действительно хороший и ясный ответ! У меня два сомнения: I), что такое [0,1], который вы включили после tfidf * tfidf.T) и II). Частота обратного документа формируется из всех статей или только двух (учитывая, что у вас больше 2)? –

+2

@AndresAzqueta [0,1] - это позиции в матрице для подобия, поскольку два текстовых ввода создадут симметричную матрицу 2x2. –

+1

@Renaud, Спасибо за ваш полный код. Для тех, кто столкнулся с ошибкой с запросом nltk.download(), вы можете легко выполнить nltk.download ('punkt'). Вам не нужно загружать все. – 1man

16

Это старый вопрос, но я нашел, что это можно сделать easi с Spacy. Как только документ будет прочитан, простой api similarity можно использовать для поиска сходства косинусов между векторами документа.

import spacy 
nlp = spacy.load('en') 
doc1 = nlp(u'Hello hi there!') 
doc2 = nlp(u'Hello hi there!') 
doc3 = nlp(u'Hey whatsup?') 

print doc1.similarity(doc2) # 0.999999954642 
print doc2.similarity(doc3) # 0.699032527716 
print doc1.similarity(doc3) # 0.699032527716 
+0

Интересно, почему сходство между doc1 и doc2 равно 0.999999954642, а не 1.0 – JordanBelf

+3

. Число чисел с плавающей запятой JordanBelf немного блуждает по большинству языков, так как они не могут иметь неограниченную точность в цифровых представлениях. например операции с плавающей запятой или создание иррациональных чисел всегда имеют крошечные ошибки округления, которые затем умножаются. Это недостаток такого гибкого представления в масштабных терминах. – scipilot

+0

Что такое функция расстояния, использующая метод сходства в этом случае? – ikel

0

Если вы больше заинтересованы в измерении семантического сходства двух частей текста, я предлагаю взглянуть на this gitlab project.Вы можете запустить его как сервер, есть также предварительно построенная модель, которую вы можете легко использовать для измерения сходства двух фрагментов текста; даже если он в основном подготовлен для измерения сходства двух предложений, вы все равно можете использовать его в своем случае. Он написан в java, но вы можете запустить его как службу RESTful.

Другой вариант также - DKPro Similarity, который представляет собой библиотеку с различным алгоритмом для измерения сходства текстов. Однако он также написан в java.

Смежные вопросы