Em primeiro lugar, se você deseja extrair recursos de contagem e aplicar normalização TF-IDF e normalização euclidiana por linha, você pode fazer isso em uma operação com 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>
Agora, para encontrar as distâncias de cosseno de um documento (por exemplo, o primeiro no conjunto de dados) e todos os outros, você só precisa calcular os produtos escalares do primeiro vetor com todos os outros, pois os vetores tfidf já estão normalizados por linha.
Conforme explicado por Chris Clark nos comentários e aqui semelhança de cossenos não leva em consideração a magnitude dos vetores. Normalizado por linha tem uma magnitude de 1 e, portanto, o Kernel Linear é suficiente para calcular os valores de similaridade.
A API de matriz esparsa scipy é um pouco estranha (não tão flexível quanto matrizes numpy N-dimensionais densas). Para obter o primeiro vetor, você precisa dividir a matriz em linha para obter uma submatriz com uma única linha:
>>> tfidf[0:1]
<1x130088 sparse matrix of type '<type 'numpy.float64'>'
with 89 stored elements in Compressed Sparse Row format>
O scikit-learn já fornece métricas de pares (também conhecidas como kernels, no jargão do aprendizado de máquina) que funcionam tanto para representações densas quanto esparsas de coleções de vetores. Nesse caso, precisamos de um produto escalar que também é conhecido como kernel linear:
>>> 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])
Portanto, para encontrar os 5 principais documentos relacionados, podemos usar argsort
e um pouco de divisão de matriz negativa (a maioria dos documentos relacionados tem valores de similaridade de cosseno mais altos, portanto, no final da matriz de índices classificados):
>>> 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 ])
O primeiro resultado é uma verificação de sanidade: encontramos o documento de consulta como o documento mais semelhante com uma pontuação de similaridade de cosseno de 1, que possui o seguinte texto:
>>> print twenty.data[0]
From: lerxst@wam.umd.edu (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 ----
O segundo documento mais semelhante é uma resposta que cita a mensagem original, portanto, tem muitas palavras em comum:
>>> print twenty.data[958]
From: rseymour@reed.edu (Robert Seymour)
Subject: Re: WHAT car is this!?
Article-I.D.: reed.1993Apr21.032905.29286
Reply-To: rseymour@reed.edu
Organization: Reed College, Portland, OR
Lines: 26
In article <1993Apr20.174246.14375@wam.umd.edu> lerxst@wam.umd.edu (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 rseymour@reed.edu
Physics and Philosophy, Reed College (NeXTmail accepted)
Artificial Life Project Reed College
Reed Solar Energy Project (SolTrain) Portland, OR