दो पाठ दस्तावेजों के बीच समानता की गणना कैसे करें?


207

मैं एनएलपी परियोजना पर काम कर रहा हूं, किसी भी प्रोग्रामिंग भाषा में (हालांकि पायथन मेरी प्राथमिकता होगी)।

मैं दो दस्तावेज लेना चाहता हूं और निर्धारित करना चाहता हूं कि वे कितने समान हैं।


1
इसी तरह के सवाल यहां stackoverflow.com/questions/101569/… कुछ अच्छे जवाबों को

जवाबों:


292

ऐसा करने का सामान्य तरीका यह है कि दस्तावेजों को TF-IDF वैक्टर में बदल दिया जाए और फिर उनके बीच कॉस्मिक समानता की गणना की जाए। सूचना पुनर्प्राप्ति (आईआर) पर कोई भी पाठ्यपुस्तक इसमें शामिल है। जासूसी देखें। सूचना पुनर्प्राप्ति का परिचय , जो मुफ़्त है और ऑनलाइन उपलब्ध है।

कम्प्यूटिंग Pairwise समानताएँ

TF-IDF (और इसी तरह के टेक्स्ट ट्रांसफ़ॉर्मेशन) पायथन पैकेज में लागू होते हैं 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

या, यदि दस्तावेज़ सादे तार हैं,

>>> 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-TF-IDF कार्यान्वयन में शामिल था।]

परिणामों की व्याख्या करना

ऊपर से, pairwise_similarityएक स्किपी स्पार्स मैट्रिक्स है जो आकार में चौकोर है, जिसमें कोर और डॉक्यूमेंट की संख्या के बराबर पंक्तियों और कॉलमों की संख्या है।

>>> pairwise_similarity                                                                                                                                                                                                                                      
<5x5 sparse matrix of type '<class 'numpy.float64'>'
    with 17 stored elements in Compressed Sparse Row format>

आप विरल ऐरे को न्यूपे सरणी में बदल सकते हैं .toarray()या इसके द्वारा .A:

>>> pairwise_similarity.toarray()                                                                                                                                                                                                                            
array([[1.        , 0.17668795, 0.27056873, 0.        , 0.        ],
       [0.17668795, 1.        , 0.15439436, 0.        , 0.        ],
       [0.27056873, 0.15439436, 1.        , 0.19635649, 0.16815247],
       [0.        , 0.        , 0.19635649, 1.        , 0.54499756],
       [0.        , 0.        , 0.16815247, 0.54499756, 1.        ]])

मान लें कि हम दस्तावेज़ को अंतिम दस्तावेज़ के समान ढूंढना चाहते हैं, "स्किटिट-लर्न डॉक्स ऑरेंज और ब्लू हैं"। इस दस्तावेज़ में सूचकांक 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 सरणी में कनवर्ट करने के बजाय, आप कर सकते हैं:

>>> n, _ = pairwise_similarity.shape                                                                                                                                                                                                                         
>>> pairwise_similarity[np.arange(n), np.arange(n)] = -1.0
>>> pairwise_similarity[input_idx].argmax()                                                                                                                                                                                                                  
3

1
@larsmans क्या आप सरणी को थोड़ा समझा सकते हैं यदि संभव हो, तो मुझे इस सरणी को कैसे पढ़ना चाहिए। पहले दो वाक्य पहले दो वाक्यों के बीच समानता है?
ऐड-सेमी-कॉलोन्स

1
@ नल-परिकल्पना: स्थिति में (i, j), आप दस्तावेज़ i और दस्तावेज़ j के बीच समानता स्कोर पाते हैं। तो, स्थिति (0,2) पहले दस्तावेज़ और तीसरे (शून्य-आधारित अनुक्रमण का उपयोग करके) के बीच समानता मूल्य है, जो कि एक ही मूल्य है जो आपको (2,0) पर मिलता है, क्योंकि कोसाइन समानता समानता है।
फ्रेड फू

1
अगर मैं 1 के विकर्ण के बाहर के सभी मूल्यों को औसत कर रहा था, तो क्या यह एक एकल स्कोर प्राप्त करने का एक अच्छा तरीका होगा कि चार दस्तावेज़ एक-दूसरे के समान कैसे हैं? यदि नहीं, तो क्या कई दस्तावेजों के बीच समग्र समानता का निर्धारण करने का एक बेहतर तरीका है?
user301752

2
@ user301752: आप tf-idf वैक्टर के तत्व-वार माध्य (जैसे k- साधन करेंगे) के साथ ले सकते हैं X.mean(axis=0), फिर उस अर्थ से औसत / अधिकतम / माध्य (∗) यूक्लिडियन दूरी की गणना करें। (Wh) जो भी आपके फैंस को चुनें।
फ्रेड फू

1
@ गंभीर: मैंने उदाहरण कोड को वर्तमान स्किकिट-लर्न एपीआई में अपडेट किया; आप नए कोड को आज़माना चाहते हैं।
फ्रेड फू

87

@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')

@ रेनॉड, वास्तव में अच्छा और स्पष्ट जवाब! मुझे दो संदेह हैं: I) क्या है [0,1] जिसे आप tfidf * tfidf.T के बाद शामिल करते हैं) और II) उलटा दस्तावेज़ आवृत्ति सभी लेखों से या सिर्फ दो से बनता है (यह विचार करते हुए कि आपके पास 2 से अधिक है) ?
अर्थशास्त्री_आयुवास्का

2
@AndresAzqueta [0,1] मैट्रिक्स में स्थितियां हैं जो समानता के लिए दो पाठ इनपुट्स 2x2 सममित मैट्रिक्स बनाएंगे।
फिलिप बर्गस्ट्रॉम

1
@ रेनॉड, आपके पूर्ण कोड के लिए धन्यवाद। उन लोगों के लिए जिन्होंने nltk.download () से पूछते हुए त्रुटि का सामना किया, आप आसानी से nltk.download ('पंकट') कर सकते हैं। आपको सब कुछ डाउनलोड करने की आवश्यकता नहीं है।
1

@ रेनॉड मुझे एक अधिक मौलिक समस्या नहीं है। पाठ के कौन से तार होने चाहिए fitऔर कौन से transform?
जॉन स्ट्रॉड

@ जॉनस्ट्रोइड मैं आपके प्रश्न को नहीं समझता, क्षमा करें आप सुधार कर सकते हैं?
रेनॉड

45

यह एक पुराना प्रश्न है, लेकिन मैंने पाया कि यह स्पैसी के साथ आसानी से किया जा सकता है । एक बार दस्तावेज़ को पढ़ने के बाद, 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

2
मुझे आश्चर्य है कि doc1 और doc2 के बीच समानता 0.999999954642 है और 1.0 नहीं
जॉर्डनब्लफ

4
@JordanBelf फ़्लोटिंग पॉइंट नंबरों को अधिकांश भाषाओं में थोड़ा घूमना पड़ता है - क्योंकि वे डिजिटल अभ्यावेदन में असीमित परिशुद्धता नहीं रख सकते हैं। उदाहरण के लिए फ़्लोटिंग पॉइंट ऑपरेशंस पर या अपरिमेय संख्याओं के निर्माण में हमेशा छोटी गोलाई वाली त्रुटियाँ होती हैं, जो तब बढ़ती हैं। यह पैमाने के संदर्भ में इस तरह के एक लचीले प्रतिनिधित्व के नकारात्मक पक्ष है।
स्काइपीलॉट

2
इस मामले में समानता विधि क्या है?
3

आप खोजने "एन" कोई समस्या है तो स्थापित निम्नलिखित पिप चलाने spacy && अजगर -m spacy डाउनलोड एन
Cybernetic


17

आम तौर पर दो दस्तावेजों के बीच एक कोसाइन समानता का उपयोग दस्तावेजों की समानता माप के रूप में किया जाता है। जावा में, आप ऐसा करने के लिए Lucene (यदि आपका संग्रह बहुत बड़ा है) या LingPipe का उपयोग कर सकते हैं । मूल अवधारणा हर दस्तावेज़ में शब्दों को गिनना और वैक्टर शब्द के डॉट उत्पाद की गणना करना होगा। पुस्तकालय इस सामान्य दृष्टिकोण पर कई सुधार प्रदान करते हैं, जैसे उलटे दस्तावेज़ आवृत्तियों का उपयोग करना और tf-idf वैक्टरों की गणना करना। यदि आप कुछ कॉप्लेक्स करना चाह रहे हैं, तो लिन्गिपाइप एलएसए समानता की गणना दस्तावेजों के बीच करने के तरीके भी प्रदान करता है जो कोसाइन समानता की तुलना में बेहतर परिणाम देता है। पायथन के लिए, आप एनएलटीके का उपयोग कर सकते हैं ।


4
ध्यान दें कि "एलएसए समानता" नहीं है। एलएसए एक वेक्टर स्पेस की आयामीता को कम करने की एक विधि है (या तो चीजों को गति देने के लिए या शब्दों के बजाय विषयों को मॉडल करने के लिए)। एक ही समानता मेट्रिक्स जो BOW और tf-idf के साथ उपयोग किए जाते हैं, उन्हें LSA (cosine समानता, यूक्लिडियन समानता, BM25,…) के साथ उपयोग किया जा सकता है।
15

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)

अधिक जानकारी: https://tfhub.dev/google/universal-sentence-encoder/2


हाय इस उदाहरण के लिए धन्यवाद मुझे बाहर TF कोशिश करने के लिए प्रोत्साहित - वस्तु "एनपी" कहाँ से आना चाहिए?
ओपन फूड ब्रोकर

1
UPD ओके, मैंने प्लॉट के लिए numpy, matplotlib और सिस्टम TK TKthon बाइंडिंग स्थापित किया है और यह काम करता है !!
ओपन फूड ब्रोकर

1
बस मामले में (खेद पंक्ति विराम की कमी के लिए): एन पी के रूप में plt आयात numpy के रूप में हब आयात matplotlib.pyplot रूप tf आयात tensorflow_hub के रूप में आयात tensorflow
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)

4
यदि आप बड़ी संख्या में डॉक्स के साथ काम करने जा रहे हैं तो डिफ्लिब बहुत धीमा है।
फ़िओ अर्कार Lwin

2

आप इस ऑनलाइन सेवा को cosine दस्तावेज़ समानता 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

विभेदक अनुक्रमिक माचिस का उपयोग कर रहा है? यदि हाँ, तो अजगर में एक साधारण कार्य difflib आयात से ____________________________________ काम करेगा SequenceMatcher def isStringSimilar (a, b): अनुपात = SequenceMatcher (कोई नहीं, b) .ratio () वापसी अनुपात __________________________
रुद्रेश अजगांवकर

2

यदि आप पाठ के दो टुकड़ों की शब्दार्थ समानता को मापने में अधिक रुचि रखते हैं, तो मेरा सुझाव है कि इस गीतालाब परियोजना पर एक नज़र डालें । आप इसे सर्वर के रूप में चला सकते हैं, एक पूर्व-निर्मित मॉडल भी है जिसका उपयोग आप आसानी से पाठ के दो टुकड़ों की समानता को मापने के लिए कर सकते हैं; भले ही यह ज्यादातर दो वाक्यों की समानता को मापने के लिए प्रशिक्षित किया जाता है, फिर भी आप इसे अपने मामले में उपयोग कर सकते हैं। यह जावा में लिखा गया है, लेकिन आप इसे एक सेवा के रूप में चला सकते हैं।

एक अन्य विकल्प डीकेप्रो समानता भी है जो ग्रंथों की समानता को मापने के लिए विभिन्न एल्गोरिदम के साथ एक पुस्तकालय है। हालाँकि, इसे जावा में भी लिखा जाता है।

कोड उदाहरण:

// 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);

2

बहुत कम डेटासेट के साथ वाक्य समानता को खोजने के लिए और उच्च सटीकता प्राप्त करने के लिए आप नीचे दिए गए पायथन पैकेज का उपयोग कर सकते हैं जो पहले से प्रशिक्षित किए गए कार्य का उपयोग कर रहा है,

pip install similar-sentences

मैंने बस यही कोशिश की है, लेकिन यह प्रत्येक वाक्य की समानता को मुख्य एक के साथ देता है, लेकिन क्या सभी वाक्य बनाने के लिए कोई तरीका है। एक प्रशिक्षण को एक वर्ग के रूप में बनाना और स्कोर प्राप्त करना है कि यह सभी परीक्षाओं में कितना आत्मविश्वास से मेल खाता है। ?
गुरु तेजा

1
हाँ, आप कोशिश कर सकते हैं .batch_predict (BatchFile, NumberOfPrediction) जो Results.xls को कॉलम के रूप में आउटपुट देगा ['वाक्य', 'सुझाव', 'स्कोर']
शंकर गणेश जयरामन

1

सिंथेटिक समानता के लिए समानता का पता लगाने के 3 आसान तरीके हो सकते हैं।

  • Word2Vec
  • दस्ताना
  • Tfidf या countvectorizer

शब्दार्थ समानता के लिए कोई भी BERT एम्बेडिंग का उपयोग कर सकता है और दस्तावेज़ एम्बेडिंग प्राप्त करने के लिए एक अलग शब्द पूलिंग रणनीति का प्रयास कर सकता है और फिर दस्तावेज़ एम्बेडिंग पर कोज़ाइन समानता लागू कर सकता है।

एक उन्नत पद्धति समानता प्राप्त करने के लिए BERT SCORE का उपयोग कर सकती है। BERT SCORE

शोध पत्र लिंक: https://arxiv.org/abs/1904.09675

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.