Saya melihat bekerja pada proyek NLP, dalam bahasa pemrograman apa pun (meskipun Python akan menjadi pilihan saya).
Saya ingin mengambil dua dokumen dan menentukan seberapa miripnya.
Saya melihat bekerja pada proyek NLP, dalam bahasa pemrograman apa pun (meskipun Python akan menjadi pilihan saya).
Saya ingin mengambil dua dokumen dan menentukan seberapa miripnya.
Jawaban:
Cara umum untuk melakukan ini adalah mengubah dokumen menjadi vektor TF-IDF dan kemudian menghitung kesamaan cosinus di antara mereka. Buku teks tentang pencarian informasi (IR) apa pun mencakup ini. Lihat esp. Pengantar Pengambilan Informasi , yang gratis dan tersedia secara online.
TF-IDF (dan transformasi teks serupa) diimplementasikan dalam paket Python Gensim dan scikit-learn . Dalam paket terakhir, menghitung persamaan cosinus semudah
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
atau, jika dokumennya berupa string biasa,
>>> 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
meskipun Gensim mungkin memiliki lebih banyak opsi untuk tugas semacam ini.
Lihat juga pertanyaan ini .
[Penafian: Saya terlibat dalam implementasi scikit-learn TF-IDF.]
Dari atas, pairwise_similarity
adalah matriks jarang Scipy yang berbentuk persegi, dengan jumlah baris dan kolom sama dengan jumlah dokumen dalam korpus.
>>> pairwise_similarity
<5x5 sparse matrix of type '<class 'numpy.float64'>'
with 17 stored elements in Compressed Sparse Row format>
Anda bisa mengonversi array jarang ke array NumPy melalui .toarray()
atau .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. ]])
Katakanlah kita ingin menemukan dokumen yang paling mirip dengan dokumen terakhir, "Dokumen scikit-belajar adalah Oranye dan Biru". Dokumen ini memiliki indeks 4 in corpus
. Anda dapat menemukan indeks dokumen yang paling mirip dengan mengambil argmax dari baris itu, tetapi pertama-tama Anda harus menutupi 1, yang mewakili kesamaan dari setiap dokumen dengan dirinya sendiri . Anda dapat melakukan yang terakhir melalui np.fill_diagonal()
, dan yang pertama melalui 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'
Catatan: tujuan menggunakan matriks jarang adalah untuk menghemat (jumlah ruang yang besar) untuk korpus besar & kosakata. Alih-alih mengonversi ke array NumPy, Anda bisa melakukan:
>>> n, _ = pairwise_similarity.shape
>>> pairwise_similarity[np.arange(n), np.arange(n)] = -1.0
>>> pairwise_similarity[input_idx].argmax()
3
X.mean(axis=0)
, kemudian menghitung rata-rata / maksimum / median (∗) jarak Euclidean dari rata-rata itu. (∗) Pilih yang mana yang Anda sukai.
Identik dengan @ larsman, tetapi dengan beberapa preprocessing
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
, dan yang mana transform
?
Ini pertanyaan lama, tetapi saya menemukan ini dapat dilakukan dengan mudah dengan Spacy . Setelah dokumen dibaca, api sederhana similarity
dapat digunakan untuk menemukan kesamaan cosinus antara vektor dokumen.
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
Umumnya kesamaan cosinus antara dua dokumen digunakan sebagai ukuran kesamaan dokumen. Di Jawa, Anda dapat menggunakan Lucene (jika koleksi Anda cukup besar) atau LingPipe untuk melakukan ini. Konsep dasar akan menghitung istilah dalam setiap dokumen dan menghitung titik produk dari vektor istilah. Perpustakaan memang memberikan beberapa perbaikan atas pendekatan umum ini, misalnya menggunakan frekuensi dokumen terbalik dan menghitung vektor tf-idf. Jika Anda ingin melakukan sesuatu copmlex, LingPipe juga menyediakan metode untuk menghitung kesamaan LSA antara dokumen yang memberikan hasil yang lebih baik daripada cosine similarity. Untuk Python, Anda bisa menggunakan NLTK .
Jika Anda mencari sesuatu yang sangat akurat, Anda perlu menggunakan beberapa alat yang lebih baik daripada tf-idf. Encoder kalimat universal adalah salah satu yang paling akurat untuk menemukan kesamaan antara dua bagian teks. Google menyediakan model pra-pelatihan yang dapat Anda gunakan untuk aplikasi Anda sendiri tanpa perlu melatih apa pun. Pertama, Anda harus menginstal tensorflow dan tensorflow-hub:
pip install tensorflow
pip install tensorflow_hub
Kode di bawah ini memungkinkan Anda mengonversi teks apa pun menjadi representasi vektor dengan panjang tetap dan kemudian Anda dapat menggunakan produk titik untuk mengetahui kesamaan di antara mereka
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)
dan kode untuk merencanakan:
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()
seperti yang Anda lihat, kesamaan yang paling mirip adalah antara teks dengan diri mereka sendiri dan kemudian dengan teks dekat dalam makna.
PENTING : pertama kali Anda menjalankan kode itu akan lambat karena perlu mengunduh model. jika Anda ingin mencegahnya mengunduh model lagi dan menggunakan model lokal Anda harus membuat folder untuk cache dan menambahkannya ke variabel lingkungan dan kemudian setelah pertama kali berjalan gunakan jalur itu:
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)
Informasi lebih lanjut: https://tfhub.dev/google/universal-sentence-encoder/2
Berikut ini sedikit aplikasi untuk membantu Anda memulai ...
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)
Anda mungkin ingin mencoba layanan online ini untuk kesamaan dokumen cosinus 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
Jika Anda lebih tertarik mengukur kesamaan semantik dari dua bagian teks, saya sarankan lihat proyek gitlab ini . Anda dapat menjalankannya sebagai server, ada juga model pra-dibangun yang dapat Anda gunakan dengan mudah untuk mengukur kesamaan dua potong teks; meskipun sebagian besar dilatih untuk mengukur kemiripan dua kalimat, Anda masih dapat menggunakannya dalam kasus Anda. Ini ditulis dalam java tetapi Anda dapat menjalankannya sebagai layanan RESTful.
Pilihan lain juga adalah DKPro Similarity yang merupakan perpustakaan dengan berbagai algoritma untuk mengukur kesamaan teks. Namun, ini juga ditulis dalam java.
contoh kode:
// 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);
Untuk menemukan kesamaan kalimat dengan dataset yang sangat sedikit dan untuk mendapatkan akurasi tinggi Anda dapat menggunakan paket python di bawah ini yang menggunakan model BERT yang telah dilatih sebelumnya,
pip install similar-sentences
Untuk Kesamaan Sintaksis Ada 3 cara mudah untuk mendeteksi kesamaan.
Untuk Semantic Similarity One dapat menggunakan BERT Embedding dan mencoba strategi kumpulan kata yang berbeda untuk mendapatkan penyematan dokumen dan kemudian menerapkan kesamaan cosinus pada penyematan dokumen.
Metodologi canggih dapat menggunakan BERT SCORE untuk mendapatkan kesamaan.
Tautan Makalah Penelitian: https://arxiv.org/abs/1904.09675