Sie haben den Typ wordset1
und wordset2
nicht erwähnt. Ich nehme an, sie sind beide strings
.
Sie haben Ihre Entfernung als Wortzählung definiert und eine schlechte Bewertung erhalten. Es ist offensichtlich, dass die Textlänge kein gutes Unähnlichkeitsmaß ist: zwei E-Mails unterschiedlicher Größe können über dasselbe sprechen, während zwei E-Mails gleicher Größe über ganz andere Dinge sprechen.
So, wie oben vorgeschlagen, können Sie versuchen, und stattdessen nach ähnlichen Worten überprüfen:
import numpy as np
def distance(wordset1, wordset2):
wordset1 = set(wordset1.split())
wordset2 = set(wordset2.split())
common_words = wordset1 & wordset2
if common_words:
return 1/len(common_words)
else:
# They don't share any word. They are infinitely different.
return np.inf
Das Problem dabei ist, dass zwei große E-Mails sind eher Worte als zwei kleine teilen und diese Metrik würde diejenigen bevorzugen, die sie "ähnlicher machen" als die Kleinen. Wie lösen wir das? Naja, wir normalisieren die Metrik irgendwie:
Das scheint cool, aber ignoriert völlig die FREQUENZ der Wörter. Um dies zu berücksichtigen, können wir das Modell Bag-of-words verwenden. Das heißt, erstellen Sie eine Liste aller möglichen Wörter und Histogramm ihre Erscheinung in jedem Dokument. Lassen Sie uns CountVectorizer Implementierung von verwenden Scikit-Learn unsere Aufgabe eaiser zu machen:
from sklearn.feature_extraction.text import CountVectorizer
def distance(wordset1, wordset2):
model = CountVectorizer()
X = model.fit_transform([wordset1, wordset2]).toarray()
# uses Euclidean distance between bags.
return np.linalg.norm(X[0] - X[1])
Aber jetzt zwei Paare von E-Mails betrachten. Die E-Mails in dem ersten Paar bestehen aus perfekt geschriebenem Englisch, das mit "kleinen" Wörtern gefüllt ist (z. B. a
, an
, and
, that
), die notwendig sind, damit es grammatikalisch korrekt ist. Die E-Mails im zweiten Paar sind anders: nur die Keywords enthalten, ist es extrem trocken. Sie sehen, die Chancen stehen gut, dass das erste Paar ähnlicher ist als das zweite. Das passiert, weil wir derzeit alle Wörter gleich schreiben, während wir die BEDEUTENDEN Wörter in jedem Text priorisieren sollten. Um das zu tun, verwenden wir term frequency–inverse document frequency. Luckly, gibt es eine sehr ähnliche Implementierung in Scikit-Learn:
from sklearn.feature_extraction.text import TfidfVectorizer
def distance(wordset1, wordset2):
model = TfidfVectorizer()
X = model.fit_transform([wordset1, wordset2]).toarray()
similarity_matrix = X.dot(X.T)
# The dissimilarity between samples wordset1 and wordset2.
return 1-similarity_matrix[0, 1]
mehr dazu lesen Sie in diesem question. Auch duplizieren?
Sie sollten jetzt eine ziemlich gute Genauigkeit haben. Versuch es.Wenn es immer noch nicht so gut ist, wie du willst, dann müssen wir tiefer gehen ... (verstanden? Weil ... Deep-Learning). Die erste Sache ist, dass wir entweder einen Datensatz zum Trainieren benötigen oder ein bereits trainiertes Modell. Dies ist erforderlich, weil Netzwerke viele Parameter haben, die angepasst werden müssen, um nützliche Transformationen bereitzustellen.
Was bis jetzt fehlt, ist VERSTÄNDNIS. Wir histogrammierten die Wörter und streiften sie von jedem Kontext oder jeder Bedeutung. Stattdessen sollten wir sie dort belassen, wo sie sind, und Blockmuster erkennen. Wie kann das gemacht werden?
- Betten Sie die Wörter in Zahlen ein, die sich mit den verschiedenen Wortgrößen befassen.
- Fügen Sie jede Nummer (Wort eingebettet) Sequenz auf eine einzige Länge.
- Verwenden Sie konvolutionelle Netzwerke, um wichtige Funktionen aus Sequenzen zu extrahieren.
- Verwenden Sie vollständig verbundene Netzwerke, um die extrahierten Features in einen Bereich zu projizieren, der die Entfernung zwischen ähnlichen E-Mails minimiert und den Abstand zwischen nichtähnlichen E-Mails maximiert.
Lassen Sie uns Keras einfach unser Leben verwenden. Es sollte wie folgt aussehen:
# ... imports and params definitions
model = Sequential([
Embedding(max_features,
embedding_dims,
input_length=maxlen,
dropout=0.2),
Convolution1D(nb_filter=nb_filter,
filter_length=filter_length,
border_mode='valid',
activation='relu',
subsample_length=1),
MaxPooling1D(pool_length=model.output_shape[1]),
Flatten(),
Dense(256, activation='relu'),
])
# ... train or load model weights.
def distance(wordset1, wordset2):
global model
# X = ... # Embed both emails.
X = sequence.pad_sequences(X, maxlen=maxlen)
y = model.predict(X)
# Euclidean distance between emails.
return np.linalg.norm(y[0]-y[1])
Es gibt ein praktisches Beispiel für Satzverarbeitung, die Sie Keras github repo überprüfen können. Auch jemand löst genau dieses Problem mit einem siamesischen wiederkehrenden Netzwerk in diesem stackoverflow question.
Nun, ich hoffe, das gibt Ihnen eine Richtung. :-)
Vielleicht kann die Länge der Kreuzung beider Wortsätze eine bessere Abstandsfunktion sein. –
Diese Funktion könnte eine Zeile sein. 'math.abs (len1 - len2)' –