2017-12-18 1 views
0

Ich habe einen Ordner mit Hunderten von TXT-Dateien, die ich für Ähnlichkeit analysieren muss. Im Folgenden finden Sie ein Beispiel für ein Skript, mit dem die Ähnlichkeitsanalyse ausgeführt wird. Am Ende bekomme ich ein Array oder eine Matrix, die ich plotten kann usw.Zählen von Matrixpaaren mit einem Schwellenwert

Ich würde gerne sehen, wie viele Paare gibt es mit cos_similarity > 0.5 (oder einen anderen Schwellenwert, den ich zu verwenden), Entfernen cos_similarity == 1, wenn ich die gleichen Dateien vergleichen , Na sicher.

Zweitens brauche ich eine Liste dieser Paare basierend auf Dateinamen.

die Ausgabe für das Beispiel so unten würde wie folgt aussehen:

1

und

["doc1", "doc4"]

wirklich Werden Ihre Hilfe zu schätzen wissen, wie ich ein bisschen das Gefühl, nicht in welche Richtung zu wissen, verloren gehen.

Dies ist ein Beispiel für mein Skript, um die Matrix zu erhalten:

doc1 = "Amazon's promise of next-day deliveries could be investigated amid customer complaints that it is failing to meet that pledge." 
doc2 = "The BBC has been inundated with comments from Amazon Prime customers. Most reported problems with deliveries." 
doc3 = "An Amazon spokesman told the BBC the ASA had confirmed to it there was no investigation at this time." 
doc4 = "Amazon's promise of next-day deliveries could be investigated amid customer complaints..." 
documents = [doc1, doc2, doc3, doc4] 

# In my real script I iterate through a folder (path) with txt files like this: 
#def read_text(path): 
# documents = [] 
# for filename in glob.iglob(path+'*.txt'): 
#  _file = open(filename, 'r') 
#  text = _file.read() 
#  documents.append(text) 
# return documents 

import nltk, string, numpy 
nltk.download('punkt') # first-time use only 
stemmer = nltk.stem.porter.PorterStemmer() 
def StemTokens(tokens): 
    return [stemmer.stem(token) for token in tokens] 
remove_punct_dict = dict((ord(punct), None) for punct in string.punctuation) 
def StemNormalize(text): 
    return StemTokens(nltk.word_tokenize(text.lower().translate(remove_punct_dict))) 

nltk.download('wordnet') # first-time use only 
lemmer = nltk.stem.WordNetLemmatizer() 
def LemTokens(tokens): 
    return [lemmer.lemmatize(token) for token in tokens] 
remove_punct_dict = dict((ord(punct), None) for punct in string.punctuation) 
def LemNormalize(text): 
    return LemTokens(nltk.word_tokenize(text.lower().translate(remove_punct_dict))) 

from sklearn.feature_extraction.text import CountVectorizer 
LemVectorizer = CountVectorizer(tokenizer=LemNormalize, stop_words='english') 
LemVectorizer.fit_transform(documents) 
tf_matrix = LemVectorizer.transform(documents).toarray() 

from sklearn.feature_extraction.text import TfidfTransformer 
tfidfTran = TfidfTransformer(norm="l2") 
tfidfTran.fit(tf_matrix) 
tfidf_matrix = tfidfTran.transform(tf_matrix) 
cos_similarity_matrix = (tfidf_matrix * tfidf_matrix.T).toarray() 

from sklearn.feature_extraction.text import TfidfVectorizer 
TfidfVec = TfidfVectorizer(tokenizer=LemNormalize, stop_words='english') 
def cos_similarity(textlist): 
    tfidf = TfidfVec.fit_transform(textlist) 
    return (tfidf * tfidf.T).toarray() 
cos_similarity(documents) 

Out:

array([[ 1.  , 0.1459739 , 0.03613371, 0.76357693], 
     [ 0.1459739 , 1.  , 0.11459266, 0.19117117], 
     [ 0.03613371, 0.11459266, 1.  , 0.04732164], 
     [ 0.76357693, 0.19117117, 0.04732164, 1.  ]]) 
+0

Schau! Im vorherigen Ausschnitt kann ich sehen, dass Sie Funktionen links und rechts erstellen. Wir erstellen nur Funktionen, wenn wir immer wieder dasselbe Stück Code verwenden. Um Zeit und Aufwand zu sparen, erstellen wir Funktionen. Aber wenn die Funktion nur eine Zeile ist oder wir sie einmal oder so verwenden, ist es besser, wenn wir sie nicht erstellen, was den Code sauberer, lesbarer und verständlicher macht. –

+0

Sie haben absolut recht! Ich habe gerade diesen Ausschnitt aus einem Online-Tutorial genommen, aber ich werde es aufräumen, wie Sie es vorgeschlagen haben. – aviss

+0

keep rockin ', bro –

Antwort

1

Wie ich Ihre Frage verstanden, möchten Sie eine Funktion erstellen, die die Ausgabe numpy Array liest und einen bestimmten Wert (Schwellenwert), um zwei Dinge zurückzugeben:

  • Wie viele Dokumente sind größer oder gleich der angegebenen Schwelle alt
  • die Namen dieser Dokumente. So

, hier habe ich die folgende Funktion aus, die drei Argumente verwendet:

  • der Ausgang numpy Array von cos_similarity() Funktion.
  • Liste der Dokumentennamen.
  • eine bestimmte Anzahl (Schwelle).

Und hier ist es:

def get_docs(arr, docs_names, threshold): 
    output_tuples = [] 
    for row in range(len(arr)): 
     lst = [row+1+idx for idx, num in \ 
        enumerate(arr[row, row+1:]) if num >= threshold] 
     for item in lst: 
      output_tuples.append((docs_names[row], docs_names[item])) 

    return len(output_tuples), output_tuples 

ist es in Aktion sehen lassen:

>>> docs_names = ["doc1", "doc2", "doc3", "doc4"] 
>>> arr = cos_similarity(documents) 
>>> arr 
array([[ 1.  , 0.1459739 , 0.03613371, 0.76357693], 
    [ 0.1459739 , 1.  , 0.11459266, 0.19117117], 
    [ 0.03613371, 0.11459266, 1.  , 0.04732164], 
    [ 0.76357693, 0.19117117, 0.04732164, 1.  ]]) 
>>> threshold = 0.5 
>>> get_docs(arr, docs_names, threshold) 
(1, [('doc1', 'doc4')]) 
>>> get_docs(arr, docs_names, 1) 
(0, []) 
>>> get_docs(lst, docs_names, 0.13) 
(3, [('doc1', 'doc2'), ('doc1', 'doc4'), ('doc2', 'doc4')]) 

Mal sehen, wie diese Funktion funktioniert:

  • erste iterieren ich über jede Zeile des Nummernfeldes.
  • Zweitens iteriere ich über jedes Element in der Zeile, deren Index größer als der Index der Zeile ist. Wir durchlaufen also eine trainguale Form wie folgt: und das ist, weil jedes Dokumentpaar zweimal im gesamten Array erwähnt wird. Wir können sehen, dass die beiden Werte arr[0][1] und arr[1][0] gleich sind.Sie sollten auch bemerken, dass die diagonalen Elemente nicht enthalten sind, weil wir sicher wussten, dass sie 1 als jedes Dokument sind, ist sehr ähnlich zu sich selbst :).
  • Schließlich erhalten wir die Elemente, deren Werte größer oder gleich dem angegebenen Schwellenwert sind, und geben ihre Indizes zurück. Diese Indizes werden später verwendet, um die Dokumentennamen zu erhalten.
+0

Genau das, was ich gesucht habe. Ich danke dir sehr. Ich lese die Funktion, die Sie erstellt haben, und bin mir nicht sicher, ob ich verstehe, wie Sie diagonale Paare entfernen (num == 1). Könnten Sie bitte erklären? – aviss

+0

Ich habe meine Antwort bearbeitet. –

+0

Brilliant! Vielen Dank. – aviss

Verwandte Themen