Tôi đang xem xét làm việc trong một dự án NLP, bằng bất kỳ ngôn ngữ lập trình nào (mặc dù Python sẽ là sở thích của tôi).
Tôi muốn lấy hai tài liệu và xác định chúng giống nhau như thế nào.
Tôi đang xem xét làm việc trong một dự án NLP, bằng bất kỳ ngôn ngữ lập trình nào (mặc dù Python sẽ là sở thích của tôi).
Tôi muốn lấy hai tài liệu và xác định chúng giống nhau như thế nào.
Câu trả lời:
Cách phổ biến để làm điều này là chuyển đổi các tài liệu thành các vectơ TF-IDF và sau đó tính toán độ tương tự cosin giữa chúng. Bất kỳ sách giáo khoa về truy xuất thông tin (IR) bao gồm điều này. Xem đặc biệt. Giới thiệu về Truy xuất thông tin , miễn phí và có sẵn trực tuyến.
TF-IDF (và các phép biến đổi văn bản tương tự) được triển khai trong các gói Python Gensim và scikit-learn . Trong gói thứ hai, tính tương tự cosine dễ như
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
hoặc, nếu các tài liệu là các chuỗi đơn giản,
>>> 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
mặc dù Gensim có thể có nhiều lựa chọn hơn cho loại nhiệm vụ này.
Xem thêm câu hỏi này .
[Tuyên bố miễn trừ trách nhiệm: Tôi đã tham gia vào quá trình triển khai TF-IDF của scikit-learn.]
pairwise_similarity
Nhìn từ trên xuống, là một ma trận thưa thớt Scipy có hình vuông, với số lượng hàng và cột bằng với số lượng tài liệu trong kho văn bản.
>>> pairwise_similarity
<5x5 sparse matrix of type '<class 'numpy.float64'>'
with 17 stored elements in Compressed Sparse Row format>
Bạn có thể chuyển đổi mảng thưa sang mảng NumPy thông qua .toarray()
hoặc .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. ]])
Giả sử chúng ta muốn tìm tài liệu tương tự như tài liệu cuối cùng, "Các tài liệu tìm hiểu scikit là Orange và Blue". Tài liệu này có chỉ số 4 trong corpus
. Bạn có thể tìm thấy chỉ mục của tài liệu tương tự nhất bằng cách lấy argmax của hàng đó, nhưng trước tiên bạn sẽ cần che dấu 1, đại diện cho sự giống nhau của từng tài liệu với chính nó . Bạn có thể thực hiện cái sau thông qua np.fill_diagonal()
, và cái trước thông qua 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'
Lưu ý: mục đích của việc sử dụng ma trận thưa thớt là để tiết kiệm (một lượng không gian đáng kể) cho một kho từ vựng lớn. Thay vì chuyển đổi sang mảng NumPy, bạn có thể làm:
>>> n, _ = pairwise_similarity.shape
>>> pairwise_similarity[np.arange(n), np.arange(n)] = -1.0
>>> pairwise_similarity[input_idx].argmax()
3
X.mean(axis=0)
, sau đó tính khoảng cách trung bình / tối đa / trung bình (∗) từ trung bình đó. (∗) Chọn bất cứ thứ gì bạn thích.
Đồng nhất với @larsman, nhưng với một số tiền xử lý
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
, và những transform
gì?
Đó là một câu hỏi cũ, nhưng tôi thấy điều này có thể được thực hiện dễ dàng với Spacy . Sau khi tài liệu được đọc, một api đơn giản similarity
có thể được sử dụng để tìm sự tương tự cosin giữa các vectơ tài liệu.
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
Nói chung, độ tương tự cosin giữa hai tài liệu được sử dụng như một thước đo tương tự của tài liệu. Trong Java, bạn có thể sử dụng Lucene (nếu bộ sưu tập của bạn khá lớn) hoặc LingPipe để làm điều này. Khái niệm cơ bản sẽ là đếm các thuật ngữ trong mỗi tài liệu và tính sản phẩm chấm của các vectơ hạn. Các thư viện cung cấp một số cải tiến so với phương pháp chung này, ví dụ như sử dụng tần số tài liệu nghịch đảo và tính toán các vectơ tf-idf. Nếu bạn đang tìm cách làm một cái gì đó copmlex, LingPipe cũng cung cấp các phương pháp để tính toán độ tương tự LSA giữa các tài liệu mang lại kết quả tốt hơn so với độ tương tự cosine. Đối với Python, bạn có thể sử dụng NLTK .
Nếu bạn đang tìm kiếm một cái gì đó rất chính xác, bạn cần sử dụng một số công cụ tốt hơn tf-idf. Bộ mã hóa câu phổ là một trong những bộ chính xác nhất để tìm ra sự tương đồng giữa bất kỳ hai đoạn văn bản nào. Google cung cấp các mô hình đã được sàng lọc mà bạn có thể sử dụng cho ứng dụng của riêng mình mà không cần phải đào tạo từ đầu bất cứ điều gì. Đầu tiên, bạn phải cài đặt tenorflow và tenorflow-hub:
pip install tensorflow
pip install tensorflow_hub
Mã dưới đây cho phép bạn chuyển đổi bất kỳ văn bản nào thành biểu diễn vectơ có độ dài cố định và sau đó bạn có thể sử dụng sản phẩm dấu chấm để tìm ra sự tương đồng giữa chúng
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)
và mã cho âm mưu:
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()
như bạn có thể thấy sự tương đồng nhất là giữa các văn bản với chính chúng và sau đó với các văn bản gần gũi của chúng có ý nghĩa.
QUAN TRỌNG : lần đầu tiên bạn chạy mã, nó sẽ chậm vì cần tải xuống mô hình. nếu bạn muốn ngăn nó tải lại mô hình và sử dụng mô hình cục bộ, bạn phải tạo một thư mục cho bộ đệm và thêm nó vào biến môi trường và sau lần chạy đầu tiên, hãy sử dụng đường dẫ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)
Thêm thông tin: https://tfhub.dev/google/universal-sentence-encoder/2
Đây là một ứng dụng nhỏ để giúp bạn bắt đầu ...
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)
Bạn có thể muốn dùng thử dịch vụ trực tuyến này để có sự tương tự về tài liệu 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
Nếu bạn quan tâm hơn đến việc đo lường sự giống nhau về ngữ nghĩa của hai đoạn văn bản, tôi khuyên bạn nên xem dự án gitlab này . Bạn có thể chạy nó như một máy chủ, cũng có một mô hình được xây dựng sẵn mà bạn có thể dễ dàng sử dụng để đo lường sự giống nhau của hai đoạn văn bản; mặc dù phần lớn được đào tạo để đo lường sự giống nhau của hai câu, bạn vẫn có thể sử dụng nó trong trường hợp của mình. Nó được viết bằng java nhưng bạn có thể chạy nó như một dịch vụ RESTful.
Một tùy chọn khác cũng là DKPro Tương tự , một thư viện với nhiều thuật toán khác nhau để đo lường sự giống nhau của các văn bản. Tuy nhiên, nó cũng được viết bằng java.
mã ví dụ:
// 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);
Để tìm sự tương tự câu với rất ít tập dữ liệu và để có độ chính xác cao, bạn có thể sử dụng gói python bên dưới đang sử dụng các mô hình BERT được đào tạo trước,
pip install similar-sentences
Đối với sự tương tự cú pháp Có thể có 3 cách dễ dàng để phát hiện sự tương tự.
Đối với sự giống nhau về ngữ nghĩa Người ta có thể sử dụng Nhúng BERT và thử một chiến lược gộp từ khác để nhúng tài liệu và sau đó áp dụng độ tương tự cosine cho việc nhúng tài liệu.
Một phương pháp nâng cao có thể sử dụng BERT SCORE để có được sự tương đồng.
Liên kết tài liệu nghiên cứu: https://arxiv.org/abs/1904.09675