2013-09-25 11 views
5

Sto provando a scrivere uno script in cui calcolerò la somiglianza di pochi documenti. Voglio farlo usando LSA. Ho trovato il seguente codice e lo cambio un po '. Ho come input 3 documenti e poi come output una matrice 3x3 con la somiglianza tra loro. Voglio fare lo stesso calcolo di similarità ma solo con la libreria sklearn. È possibile?Usa analisi semantica latente con sklearn

from numpy import zeros 
from scipy.linalg import svd 
from math import log 
from numpy import asarray, sum 
from nltk.corpus import stopwords 
from sklearn.metrics.pairwise import cosine_similarity 

titles = [doc1,doc2,doc3] 
ignorechars = ''',:'!''' 

class LSA(object): 
    def __init__(self, stopwords, ignorechars): 
     self.stopwords = stopwords.words('english') 
     self.ignorechars = ignorechars 
     self.wdict = {} 
     self.dcount = 0   
    def parse(self, doc): 
     words = doc.split(); 
     for w in words: 
      w = w.lower() 
      if w in self.stopwords: 
       continue 
      elif w in self.wdict: 
       self.wdict[w].append(self.dcount) 
      else: 
       self.wdict[w] = [self.dcount] 
     self.dcount += 1 
    def build(self): 
     self.keys = [k for k in self.wdict.keys() if len(self.wdict[k]) > 1] 
     self.keys.sort() 
     self.A = zeros([len(self.keys), self.dcount]) 
     for i, k in enumerate(self.keys): 
      for d in self.wdict[k]: 
       self.A[i,d] += 1 
    def calc(self): 
     self.U, self.S, self.Vt = svd(self.A) 
     return -1*self.Vt 

    def TFIDF(self): 
     WordsPerDoc = sum(self.A, axis=0)   
     DocsPerWord = sum(asarray(self.A > 0, 'i'), axis=1) 
     rows, cols = self.A.shape 
     for i in range(rows): 
      for j in range(cols): 
       self.A[i,j] = (self.A[i,j]/WordsPerDoc[j]) * log(float(cols)/DocsPerWord[i]) 

mylsa = LSA(stopwords, ignorechars) 
for t in titles: 
    mylsa.parse(t) 
mylsa.build() 
a = mylsa.calc() 
cosine_similarity(a) 

Da @ di ogrisel risposta:

ho eseguito il seguente codice, ma la mia bocca è ancora aperta :) Quando TFIDF ha max 80% di somiglianza su due documenti con lo stesso soggetto, questo codice dare me 99,99%. Ecco perché penso che sia qualcosa che non va: P

dataset = [doc1,doc2,doc3] 
vectorizer = TfidfVectorizer(max_df=0.5,stop_words='english') 
X = vectorizer.fit_transform(dataset) 
lsa = TruncatedSVD() 
X = lsa.fit_transform(X) 
X = Normalizer(copy=False).fit_transform(X) 

cosine_similarity(X) 
+0

In quanto sopra, qual è il valore di X che stai considerando come misura di somiglianza? –

risposta

8

È possibile utilizzare il trasformatore TruncatedSVD da sklearn 0.14+: si chiama con il fit_transform sul database di documenti e quindi chiamare il metodo transform (dalla stessa TruncatedSVD metodo) sul documento di query e quindi è possibile calcolare la somiglianza del coseno dei documenti di query trasformati con il database trasformato con la funzione: sklearn.metrics.pairwise.cosine_similarity e numpy.argsort il risultato per trovare l'indice del documento più simile.

Nota che sotto il cofano, scikit-learn usa anche NumPy ma in un modo più efficiente rispetto al frammento che hai dato (usando il trucco Randomized SVD di Halko, Martinsson e Tropp).

+0

Potrebbe per favore dare un'occhiata alla domanda aggiornata? – Tasos

+0

'TruncatedSVD' ha' n_components = 2' di default. Probabilmente hai bisogno di più, per esempio 'n_components = 100'. – ogrisel

+1

Ho effettuato pochi test e tutto sopra 2, ha dato lo stesso risultato su 0.45. Invece di 0,77 di TFIDF. Cercherò di trovare un modo per migliorarlo, ma la tua risposta è corretta per questa domanda. Grazie – Tasos