Lassen Sie mich Ihnen ein weiteres von mir geschriebenes Tutorial geben. Es beantwortet Ihre Frage, erklärt aber auch, warum wir einige der Dinge tun. Ich habe auch versucht, es kurz zu machen.
Sie haben also eine, list_of_documents
die nur ein Array von Zeichenfolgen ist, und eine andere, document
die nur eine Zeichenfolge ist. Sie müssen ein solches Dokument aus dem Dokument finden list_of_documents
, das dem am ähnlichsten ist document
.
Kombinieren wir sie miteinander: documents = list_of_documents + [document]
Beginnen wir mit Abhängigkeiten. Es wird klar, warum wir jeden von ihnen verwenden.
from nltk.corpus import stopwords
import string
from nltk.tokenize import wordpunct_tokenize as tokenize
from nltk.stem.porter import PorterStemmer
from sklearn.feature_extraction.text import TfidfVectorizer
from scipy.spatial.distance import cosine
Einer der Ansätze, die verwendet werden können, ist eine Tüte mit Wörtern Word Ansatz, bei dem wir jedes Wort im Dokument unabhängig von anderen behandeln und alle zusammen in die große Tasche werfen. Unter einem Gesichtspunkt verliert es viele Informationen (wie zum Beispiel, wie die Wörter verbunden sind), aber unter einem anderen Gesichtspunkt macht es das Modell einfach.
Im Englischen und in jeder anderen menschlichen Sprache gibt es viele "nutzlose" Wörter wie "a", "the", "in", die so häufig vorkommen, dass sie nicht viel Bedeutung haben. Sie werden Stoppwörter genannt und es ist eine gute Idee, sie zu entfernen. Eine andere Sache, die man bemerken kann, ist, dass Wörter wie "analysieren", "Analysator", "Analyse" wirklich ähnlich sind. Sie haben eine gemeinsame Wurzel und alle können in nur ein Wort umgewandelt werden. Dieser Prozess wird als Stemming bezeichnet und es gibt verschiedene Stemmers, die sich in Geschwindigkeit, Aggressivität usw. unterscheiden. Also transformieren wir jedes der Dokumente in eine Liste von Wortstämmen ohne Stoppwörter. Außerdem verwerfen wir alle Satzzeichen.
porter = PorterStemmer()
stop_words = set(stopwords.words('english'))
modified_arr = [[porter.stem(i.lower()) for i in tokenize(d.translate(None, string.punctuation)) if i.lower() not in stop_words] for d in documents]
Wie hilft uns diese Wortsammlung? Stellen Sie sich vor wir 3 Taschen haben: [a, b, c]
, [a, c, a]
und [b, c, d]
. Wir können sie in der Basis in Vektoren umwandeln [a, b, c, d]
. Also haben wir mit Vektoren am Ende: [1, 1, 1, 0]
, [2, 0, 1, 0]
und [0, 1, 1, 1]
. Ähnliches gilt für unsere Dokumente (nur die Vektoren werden viel zu lang sein). Jetzt sehen wir, dass wir viele Wörter entfernt und andere gestemmt haben, um auch die Dimensionen der Vektoren zu verringern. Hier gibt es nur interessante Beobachtungen. Längere Dokumente enthalten weitaus mehr positive Elemente als kürzere. Deshalb ist es hilfreich, den Vektor zu normalisieren. Dies wird als Häufigkeit TF bezeichnet. Die Benutzer verwendeten auch zusätzliche Informationen darüber, wie oft das Wort in anderen Dokumenten verwendet wird - inverse Dokumenthäufigkeit IDF. Zusammen haben wir eine metrische TF-IDF, die einige Geschmacksrichtungen hat. Dies kann mit einer Zeile in sklearn erreicht werden :-)
modified_doc = [' '.join(i) for i in modified_arr] # this is only to convert our list of lists to list of strings that vectorizer uses.
tf_idf = TfidfVectorizer().fit_transform(modified_doc)
Tatsächlich ermöglicht der Vektorisierer viele Dinge wie das Entfernen von Stoppwörtern und das Verkleinern. Ich habe sie nur in einem separaten Schritt ausgeführt, da sklearn keine nicht englischen Stoppwörter hat, nltk jedoch.
Wir haben also alle Vektoren berechnet. Der letzte Schritt besteht darin, herauszufinden, welcher dem letzten am ähnlichsten ist. Es gibt verschiedene Möglichkeiten, dies zu erreichen. Eine davon ist die euklidische Distanz, die aus dem hier diskutierten Grund nicht so groß ist . Ein anderer Ansatz ist die Kosinusähnlichkeit . Wir iterieren alle Dokumente und berechnen die Kosinusähnlichkeit zwischen dem Dokument und dem letzten:
l = len(documents) - 1
for i in xrange(l):
minimum = (1, None)
minimum = min((cosine(tf_idf[i].todense(), tf_idf[l + 1].todense()), i), minimum)
print minimum
Jetzt enthält Minimum Informationen über das beste Dokument und seine Punktzahl.