Herhangi bir programlama dilinde (Python benim tercihim olsa da) bir NLP projesi üzerinde çalışıyorum.
İki belge almak ve bunların ne kadar benzer olduklarını belirlemek istiyorum.
Herhangi bir programlama dilinde (Python benim tercihim olsa da) bir NLP projesi üzerinde çalışıyorum.
İki belge almak ve bunların ne kadar benzer olduklarını belirlemek istiyorum.
Yanıtlar:
Bunu yapmanın yaygın yolu, belgeleri TF-IDF vektörlerine dönüştürmek ve daha sonra bunlar arasındaki kosinüs benzerliğini hesaplamaktır. Bilgi alma (IR) ile ilgili herhangi bir ders kitabı bunu kapsar. Bkz. Ücretsiz ve çevrimiçi olarak sunulan Bilgi Erişimine Giriş .
TF-IDF (ve benzeri metin dönüşümleri) Python paketleri Gensim ve scikit- learn'da uygulanır . İkinci pakette, kosinüs benzerliklerini hesaplamak kadar kolaydır
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
veya belgeler düz dizelerse,
>>> 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
Gensim'in bu tür görevler için daha fazla seçeneği olabilir.
Ayrıca bu soruya bakın .
[Feragatname: scikit-learn TF-IDF uygulamasına katıldım.]
Yukarıdan, kare şeklindeki pairwise_similarity
bir Scipy seyrek matrisi , satır ve sütunların sayısı korpustaki belge sayısına eşittir.
>>> pairwise_similarity
<5x5 sparse matrix of type '<class 'numpy.float64'>'
with 17 stored elements in Compressed Sparse Row format>
Seyrek diziyi bir NumPy dizisine .toarray()
veya yoluyla dönüştürebilirsiniz .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. ]])
Diyelim ki son belgeye en çok benzeyen belgeyi bulmak istiyoruz, "Scikit-öğren dokümanlar Turuncu ve Mavi". Bu belgede 4 inçlik dizin var corpus
. Bu satırın argmax'ını alarak en benzer belgenin dizinini bulabilirsiniz , ancak önce her belgenin kendisine benzerliğini temsil eden 1'leri maskelemeniz gerekir . Sen ikinci through yapabilirsiniz np.fill_diagonal()
ve eski through 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'
Not: seyrek bir matris kullanmanın amacı, büyük bir ceset ve kelime haznesi için (önemli miktarda alan) tasarruf etmektir. NumPy dizisine dönüştürmek yerine şunları yapabilirsiniz:
>>> n, _ = pairwise_similarity.shape
>>> pairwise_similarity[np.arange(n), np.arange(n)] = -1.0
>>> pairwise_similarity[input_idx].argmax()
3
X.mean(axis=0)
, sonra bu ortalamadan ortalama / maksimum / medyan (∗) Öklid mesafesini hesaplayabilirsiniz. (∗) Hangisinin fantezi olduğunu seç.
@Larsman ile aynı, ancak bazı ön işlemlerle
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')
fit
ve hangileri transform
?
Bu eski bir soru, ama bunun Spacy ile kolayca yapılabileceğini buldum . Belge okunduktan sonra, similarity
belge vektörleri arasındaki kosinüs benzerliğini bulmak için basit bir api kullanılabilir.
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
Genellikle iki belge arasındaki kosinüs benzerliği, belgelerin benzerlik ölçüsü olarak kullanılır. Java'da bunu yapmak için Lucene (koleksiyonunuz oldukça büyükse) veya LingPipe kullanabilirsiniz. Temel kavram, her bir belgedeki terimleri saymak ve terim vektörlerinin nokta çarpımını hesaplamak olacaktır. Kütüphaneler, bu genel yaklaşım üzerinde, örneğin ters belge frekanslarının kullanılması ve tf-idf vektörlerinin hesaplanması üzerinde çeşitli iyileştirmeler sağlar. Bir şey copmlex yapmak istiyorsanız, LingPipe ayrıca kosinüs benzerliğinden daha iyi sonuçlar veren belgeler arasındaki LSA benzerliğini hesaplamak için yöntemler sağlar. Python için NLTK kullanabilirsiniz .
Çok doğru bir şey arıyorsanız, tf-idf'den daha iyi bir araç kullanmanız gerekir. Evrensel cümle kodlayıcı , herhangi iki metin parçası arasındaki benzerliği bulmak için en doğru olanlardan biridir. Google, herhangi bir şeyi sıfırdan eğitmeye gerek kalmadan kendi uygulamanız için kullanabileceğiniz önceden hazırlanmış modeller sunmuştur. İlk olarak, tensorflow ve tensorflow-hub'ı kurmalısınız:
pip install tensorflow
pip install tensorflow_hub
Aşağıdaki kod, herhangi bir metni sabit uzunluklu vektör temsiline dönüştürmenizi sağlar ve daha sonra aralarındaki benzerliği bulmak için nokta ürününü kullanabilirsiniz.
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)
ve çizim kodu:
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()
Gördüğünüz gibi, en çok benzerlik kendileri ve sonra yakın metinleri arasındaki metinler arasındadır.
ÖNEMLİ : kodu ilk kez çalıştırdığınızda, modeli indirmesi gerektiğinden yavaş olacaktır. modeli tekrar indirmesini ve yerel modeli kullanmasını önlemek istiyorsanız, önbellek için bir klasör oluşturmanız ve ortam değişkenine eklemeniz gerekir ve ardından ilk çalıştırdıktan sonra bu yolu kullanın:
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)
Daha fazla bilgi: https://tfhub.dev/google/universal-sentence-encoder/2
İşte başlamanız için küçük bir uygulama ...
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)
Kosinüs belgesi benzerliği için bu çevrimiçi hizmeti denemek isteyebilirsiniz http://www.scurtu.it/documentSlikeity.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
İki metnin anlamsal benzerliğini ölçmekle ilgileniyorsanız , bu gitlab projesine göz atmanızı öneririm . Bir sunucu olarak çalıştırabilirsiniz, ayrıca iki metnin benzerliğini ölçmek için kolayca kullanabileceğiniz önceden oluşturulmuş bir model vardır; çoğunlukla iki cümlenin benzerliğini ölçmek için eğitilmiş olsa da, yine de sizin durumunuzda kullanabilirsiniz.Java ile yazılmıştır, ancak RESTful hizmeti olarak çalıştırabilirsiniz.
Başka bir seçenek de metinlerin benzerliğini ölçmek için çeşitli algoritmaya sahip bir kütüphane olan DKPro Similarity'dir . Ancak, java ile de yazılmıştır.
kod örneği:
// 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);
Çok daha az veri kümesiyle cümle benzerliği bulmak ve yüksek doğruluk elde etmek için önceden eğitilmiş BERT modellerini kullanan python paketini kullanabilirsiniz,
pip install similar-sentences
Sözdizimsel Benzerlik İçin Benzerliği tespit etmenin 3 kolay yolu olabilir.
Anlamsal Benzerlik için BERT Gömme kullanılabilir ve belge gömme almak için farklı bir kelime havuzu oluşturma stratejileri denemek ve sonra belge gömme kosinüs benzerliği uygulamak olabilir.
Gelişmiş bir metodoloji, benzerlik elde etmek için BERT SCORE'u kullanabilir.
Araştırma Makalesi Bağlantısı: https://arxiv.org/abs/1904.09675