Solución:
En primer lugar, si desea extraer funciones de recuento y aplicar la normalización TF-IDF y la normalización euclidiana por filas, puede hacerlo en una operación con TfidfVectorizer
:
>>> from sklearn.feature_extraction.text import TfidfVectorizer
>>> from sklearn.datasets import fetch_20newsgroups
>>> twenty = fetch_20newsgroups()
>>> tfidf = TfidfVectorizer().fit_transform(twenty.data)
>>> tfidf
<11314x130088 sparse matrix of type '<type 'numpy.float64'>'
with 1787553 stored elements in Compressed Sparse Row format>
Ahora, para encontrar las distancias de coseno de un documento (por ejemplo, el primero en el conjunto de datos) y todos los demás, solo necesita calcular los productos escalares del primer vector con todos los demás, ya que los vectores tfidf ya están normalizados por filas.
Como explica Chris Clark en los comentarios y aquí, Cosine Similarity no tiene en cuenta la magnitud de los vectores. Los normalizados por filas tienen una magnitud de 1, por lo que el núcleo lineal es suficiente para calcular los valores de similitud.
La API de matriz dispersa de scipy es un poco extraña (no tan flexible como las matrices numpy densas N-dimensionales). Para obtener el primer vector, debe dividir la matriz en filas para obtener una submatriz con una sola fila:
>>> tfidf[0:1]
<1x130088 sparse matrix of type '<type 'numpy.float64'>'
with 89 stored elements in Compressed Sparse Row format>
scikit-learn ya proporciona métricas por pares (también conocidas como kernels en el lenguaje del aprendizaje automático) que funcionan tanto para representaciones densas como dispersas de colecciones de vectores. En este caso, necesitamos un producto escalar que también se conoce como núcleo lineal:
>>> from sklearn.metrics.pairwise import linear_kernel
>>> cosine_similarities = linear_kernel(tfidf[0:1], tfidf).flatten()
>>> cosine_similarities
array([ 1. , 0.04405952, 0.11016969, ..., 0.04433602,
0.04457106, 0.03293218])
Por lo tanto, para encontrar los 5 principales documentos relacionados, podemos usar argsort
y algunos cortes de matriz negativa (la mayoría de los documentos relacionados tienen los valores de similitud de coseno más altos, por lo tanto, al final de la matriz de índices ordenados):
>>> related_docs_indices = cosine_similarities.argsort()[:-5:-1]
>>> related_docs_indices
array([ 0, 958, 10576, 3277])
>>> cosine_similarities[related_docs_indices]
array([ 1. , 0.54967926, 0.32902194, 0.2825788 ])
El primer resultado es una verificación de cordura: encontramos el documento de consulta como el documento más similar con una puntuación de similitud de coseno de 1 que tiene el siguiente texto:
>>> print twenty.data[0]
From: [email protected] (where's my thing)
Subject: WHAT car is this!?
Nntp-Posting-Host: rac3.wam.umd.edu
Organization: University of Maryland, College Park
Lines: 15
I was wondering if anyone out there could enlighten me on this car I saw
the other day. It was a 2-door sports car, looked to be from the late 60s/
early 70s. It was called a Bricklin. The doors were really small. In addition,
the front bumper was separate from the rest of the body. This is
all I know. If anyone can tellme a model name, engine specs, years
of production, where this car is made, history, or whatever info you
have on this funky looking car, please e-mail.
Thanks,
- IL
---- brought to you by your neighborhood Lerxst ----
El segundo documento más similar es una respuesta que cita el mensaje original, por lo tanto, tiene muchas palabras en común:
>>> print twenty.data[958]
From: [email protected] (Robert Seymour)
Subject: Re: WHAT car is this!?
Article-I.D.: reed.1993Apr21.032905.29286
Reply-To: [email protected]
Organization: Reed College, Portland, OR
Lines: 26
In article <[email protected]> [email protected] (where's my
thing) writes:
>
> I was wondering if anyone out there could enlighten me on this car I saw
> the other day. It was a 2-door sports car, looked to be from the late 60s/
> early 70s. It was called a Bricklin. The doors were really small. In
addition,
> the front bumper was separate from the rest of the body. This is
> all I know. If anyone can tellme a model name, engine specs, years
> of production, where this car is made, history, or whatever info you
> have on this funky looking car, please e-mail.
Bricklins were manufactured in the 70s with engines from Ford. They are rather
odd looking with the encased front bumper. There aren't a lot of them around,
but Hemmings (Motor News) ususally has ten or so listed. Basically, they are a
performance Ford with new styling slapped on top.
> ---- brought to you by your neighborhood Lerxst ----
Rush fan?
--
Robert Seymour [email protected]
Physics and Philosophy, Reed College (NeXTmail accepted)
Artificial Life Project Reed College
Reed Solar Energy Project (SolTrain) Portland, OR
Con la ayuda del comentario de @excray, me las arreglo para encontrar la respuesta: Lo que tenemos que hacer es escribir un bucle for simple para iterar sobre las dos matrices que representan los datos del tren y los datos de prueba.
Primero implemente una función lambda simple para mantener la fórmula para el cálculo del coseno:
cosine_function = lambda a, b : round(np.inner(a, b)/(LA.norm(a)*LA.norm(b)), 3)
Y luego simplemente escriba un bucle for simple para iterar sobre el vector to, la lógica es para cada “Para cada vector en trainVectorizerArray, debe encontrar la similitud del coseno con el vector en testVectorizerArray”.
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
from nltk.corpus import stopwords
import numpy as np
import numpy.linalg as LA
train_set = ["The sky is blue.", "The sun is bright."] #Documents
test_set = ["The sun in the sky is bright."] #Query
stopWords = stopwords.words('english')
vectorizer = CountVectorizer(stop_words = stopWords)
#print vectorizer
transformer = TfidfTransformer()
#print transformer
trainVectorizerArray = vectorizer.fit_transform(train_set).toarray()
testVectorizerArray = vectorizer.transform(test_set).toarray()
print 'Fit Vectorizer to train set', trainVectorizerArray
print 'Transform Vectorizer to test set', testVectorizerArray
cx = lambda a, b : round(np.inner(a, b)/(LA.norm(a)*LA.norm(b)), 3)
for vector in trainVectorizerArray:
print vector
for testV in testVectorizerArray:
print testV
cosine = cx(vector, testV)
print cosine
transformer.fit(trainVectorizerArray)
print
print transformer.transform(trainVectorizerArray).toarray()
transformer.fit(testVectorizerArray)
print
tfidf = transformer.transform(testVectorizerArray)
print tfidf.todense()
Aquí está el resultado:
Fit Vectorizer to train set [[1 0 1 0]
[0 1 0 1]]
Transform Vectorizer to test set [[0 1 1 1]]
[1 0 1 0]
[0 1 1 1]
0.408
[0 1 0 1]
[0 1 1 1]
0.816
[[ 0.70710678 0. 0.70710678 0. ]
[ 0. 0.70710678 0. 0.70710678]]
[[ 0. 0.57735027 0.57735027 0.57735027]]
Sé que es una publicación antigua. pero probé el paquete http://scikit-learn.sourceforge.net/stable/. aquí está mi código para encontrar la similitud del coseno. La pregunta era cómo calcularía la similitud de coseno con este paquete y aquí está mi código para eso
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.metrics.pairwise import cosine_similarity
from sklearn.feature_extraction.text import TfidfVectorizer
f = open("/root/Myfolder/scoringDocuments/doc1")
doc1 = str.decode(f.read(), "UTF-8", "ignore")
f = open("/root/Myfolder/scoringDocuments/doc2")
doc2 = str.decode(f.read(), "UTF-8", "ignore")
f = open("/root/Myfolder/scoringDocuments/doc3")
doc3 = str.decode(f.read(), "UTF-8", "ignore")
train_set = ["president of India",doc1, doc2, doc3]
tfidf_vectorizer = TfidfVectorizer()
tfidf_matrix_train = tfidf_vectorizer.fit_transform(train_set) #finds the tfidf score with normalization
print "cosine scores ==> ",cosine_similarity(tfidf_matrix_train[0:1], tfidf_matrix_train) #here the first element of tfidf_matrix_train is matched with other three elements
Supongamos aquí que la consulta es el primer elemento de train_set y doc1, doc2 y doc3 son los documentos que quiero clasificar con la ayuda de la similitud de coseno. entonces puedo usar este código.
También los tutoriales proporcionados en la pregunta fueron muy útiles. Aquí están todas las partes para ello parte I, parte II, parte III
la salida será la siguiente:
[[ 1. 0.07102631 0.02731343 0.06348799]]
aquí 1 representa que la consulta coincide consigo misma y los otros tres son las puntuaciones para hacer coincidir la consulta con los documentos respectivos.