Ich möchte an einem NLP-Projekt in einer beliebigen Programmiersprache arbeiten (obwohl Python meine Präferenz sein wird).
Ich möchte zwei Dokumente nehmen und feststellen, wie ähnlich sie sind.
Ich möchte an einem NLP-Projekt in einer beliebigen Programmiersprache arbeiten (obwohl Python meine Präferenz sein wird).
Ich möchte zwei Dokumente nehmen und feststellen, wie ähnlich sie sind.
Antworten:
Die übliche Methode hierfür besteht darin, die Dokumente in TF-IDF-Vektoren umzuwandeln und dann die Kosinusähnlichkeit zwischen ihnen zu berechnen. Jedes Lehrbuch zum Thema Information Retrieval (IR) behandelt dies. Siehe esp. Einführung in Information Retrieval , das kostenlos und online verfügbar ist.
TF-IDF (und ähnliche Texttransformationen ) sind in den Python-Paketen Gensim und scikit-learn implementiert . Im letzteren Paket ist die Berechnung von Kosinusähnlichkeiten so einfach wie
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
oder, wenn die Dokumente einfache Zeichenfolgen sind,
>>> 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
obwohl Gensim möglicherweise mehr Optionen für diese Art von Aufgabe hat.
Siehe auch diese Frage .
[Haftungsausschluss: Ich war an der Implementierung von Scikit-Learn TF-IDF beteiligt.]
Von oben pairwise_similarity
ist eine quadratische Scipy- Matrix mit einer quadratischen Form zu sehen, bei der die Anzahl der Zeilen und Spalten der Anzahl der Dokumente im Korpus entspricht.
>>> pairwise_similarity
<5x5 sparse matrix of type '<class 'numpy.float64'>'
with 17 stored elements in Compressed Sparse Row format>
Sie können das Sparse-Array über .toarray()
oder in ein NumPy-Array konvertieren .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. ]])
Angenommen, wir möchten das Dokument finden, das dem endgültigen Dokument am ähnlichsten ist: "Die Scikit-Lerndokumente sind Orange und Blau". Dieses Dokument hat Index 4 in corpus
. Sie können den Index des ähnlichsten Dokuments finden, indem Sie den Argmax dieser Zeile verwenden. Zuerst müssen Sie jedoch die Einsen maskieren, die die Ähnlichkeit jedes Dokuments mit sich selbst darstellen . Sie können das letztere durch np.fill_diagonal()
und das erstere durch tun 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'
Hinweis: Der Zweck der Verwendung einer spärlichen Matrix besteht darin, (viel Platz) für ein großes Korpus und Vokabular zu sparen. Anstatt in ein NumPy-Array zu konvertieren, können Sie Folgendes tun:
>>> n, _ = pairwise_similarity.shape
>>> pairwise_similarity[np.arange(n), np.arange(n)] = -1.0
>>> pairwise_similarity[input_idx].argmax()
3
X.mean(axis=0)
und dann den euklidischen Durchschnitt / Maximum / Median (∗) Abstand von diesem Mittelwert berechnen. (∗) Wählen Sie, was Ihnen gefällt.
Identisch mit @larsman, jedoch mit Vorverarbeitung
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
und welche transform
?
Es ist eine alte Frage, aber ich fand, dass dies mit Spacy leicht gemacht werden kann . Sobald das Dokument gelesen wurde, kann eine einfache API similarity
verwendet werden, um die Kosinusähnlichkeit zwischen den Dokumentvektoren zu ermitteln.
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
Im Allgemeinen wird eine Kosinusähnlichkeit zwischen zwei Dokumenten als Ähnlichkeitsmaß für Dokumente verwendet. In Java können Sie dazu Lucene (wenn Ihre Sammlung ziemlich groß ist) oder LingPipe verwenden. Das Grundkonzept wäre, die Terme in jedem Dokument zu zählen und das Punktprodukt der Termvektoren zu berechnen. Die Bibliotheken bieten gegenüber diesem allgemeinen Ansatz verschiedene Verbesserungen, z. B. die Verwendung inverser Dokumenthäufigkeiten und die Berechnung von tf-idf-Vektoren. Wenn Sie etwas Copmlexes tun möchten, bietet LingPipe auch Methoden zur Berechnung der LSA-Ähnlichkeit zwischen Dokumenten, die bessere Ergebnisse als die Cosinus-Ähnlichkeit liefern. Für Python können Sie NLTK verwenden .
Wenn Sie nach etwas sehr Genauem suchen, müssen Sie ein besseres Werkzeug als tf-idf verwenden. Der universelle Satzcodierer ist einer der genauesten, um die Ähnlichkeit zwischen zwei beliebigen Textteilen zu ermitteln. Google hat vorgefertigte Modelle bereitgestellt, die Sie für Ihre eigene Anwendung verwenden können, ohne dass Sie von Grund auf neu trainieren müssen. Zuerst müssen Sie Tensorflow und Tensorflow-Hub installieren:
pip install tensorflow
pip install tensorflow_hub
Mit dem folgenden Code können Sie jeden Text in eine Vektordarstellung fester Länge konvertieren und dann das Punktprodukt verwenden, um die Ähnlichkeit zwischen ihnen herauszufinden
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)
und der Code zum Plotten:
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()
Wie Sie sehen können, besteht die größte Ähnlichkeit zwischen Texten mit sich selbst und dann mit ihren engen Texten in der Bedeutung.
WICHTIG : Wenn Sie den Code zum ersten Mal ausführen, ist er langsam, da das Modell heruntergeladen werden muss. Wenn Sie verhindern möchten, dass das Modell erneut heruntergeladen wird und das lokale Modell verwendet wird, müssen Sie einen Ordner für den Cache erstellen und zur Umgebungsvariablen hinzufügen. Verwenden Sie dann nach dem ersten Ausführen diesen Pfad:
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)
Weitere Informationen: https://tfhub.dev/google/universal-sentence-encoder/2
Hier ist eine kleine App, mit der Sie loslegen können ...
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)
Möglicherweise möchten Sie diesen Onlinedienst für die Ähnlichkeit von Kosinusdokumenten http://www.scurtu.it/documentSimilarity.html ausprobieren
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
Wenn Sie mehr daran interessiert sind, die semantische Ähnlichkeit zweier Textteile zu messen, empfehlen wir Ihnen, sich dieses Gitlab-Projekt anzusehen . Sie können es als Server ausführen. Es gibt auch ein vorgefertigtes Modell, mit dem Sie die Ähnlichkeit zweier Textteile leicht messen können. Obwohl es hauptsächlich zum Messen der Ähnlichkeit von zwei Sätzen trainiert wurde, können Sie es in Ihrem Fall dennoch verwenden. Es ist in Java geschrieben, aber Sie können es als RESTful-Dienst ausführen.
Eine weitere Option ist DKPro Similarity , eine Bibliothek mit verschiedenen Algorithmen zur Messung der Ähnlichkeit von Texten. Es ist jedoch auch in Java geschrieben.
Codebeispiel:
// 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);
Um Satzähnlichkeit mit sehr wenig Datensatz zu finden und eine hohe Genauigkeit zu erzielen, können Sie das folgende Python-Paket verwenden, das vorab trainierte BERT-Modelle verwendet.
pip install similar-sentences
Für syntaktische Ähnlichkeit Es gibt drei einfache Möglichkeiten, Ähnlichkeit zu erkennen.
Für semantische Ähnlichkeit kann man die BERT-Einbettung verwenden und eine andere Wortpooling-Strategie ausprobieren, um die Dokumenteinbettung zu erhalten, und dann die Kosinusähnlichkeit auf die Dokumenteinbettung anwenden.
Eine erweiterte Methodik kann BERT SCORE verwenden, um Ähnlichkeit zu erzielen.
Link zum Forschungspapier: https://arxiv.org/abs/1904.09675