Eu estava seguindo um tutorial que estava disponível na Parte 1 e Parte 2 . Infelizmente, o autor não teve tempo para a seção final que envolvia o uso de similaridade de cosseno para realmente encontrar a distância entre dois documentos. Segui os exemplos do artigo com a ajuda do seguinte link de stackoverflow , incluído está o código mencionado no link acima (apenas para tornar a vida mais fácil)
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
transformer.fit(trainVectorizerArray)
print
print transformer.transform(trainVectorizerArray).toarray()
transformer.fit(testVectorizerArray)
print
tfidf = transformer.transform(testVectorizerArray)
print tfidf.todense()
como resultado do código acima, tenho a seguinte matriz
Fit Vectorizer to train set [[1 0 1 0]
[0 1 0 1]]
Transform Vectorizer to test set [[0 1 1 1]]
[[ 0.70710678 0. 0.70710678 0. ]
[ 0. 0.70710678 0. 0.70710678]]
[[ 0. 0.57735027 0.57735027 0.57735027]]
Não tenho certeza de como usar esta saída para calcular a similaridade de cosseno, eu sei como implementar a similaridade de cosseno em relação a dois vetores de comprimento semelhante, mas aqui não tenho certeza de como identificar os dois vetores.
python
machine-learning
nltk
information-retrieval
tf-idf
adicionar ponto e vírgula
fonte
fonte
Respostas:
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
: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:
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:
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):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:
O segundo documento mais semelhante é uma resposta que cita a mensagem original, portanto, tem muitas palavras em comum:
fonte
cosine_similarities = linear_kernel(tfidf, tfidf)
:?Com a ajuda do comentário de @exray, consigo descobrir a resposta, O que precisamos fazer é realmente escrever um loop for simples para iterar sobre os dois arrays que representam os dados do trem e os dados de teste.
Primeiro implemente uma função lambda simples para manter a fórmula para o cálculo do cosseno:
Em seguida, basta escrever um loop for simples para iterar sobre o vetor to, a lógica é para cada "Para cada vetor em trainVectorizerArray, você deve encontrar a similaridade do cosseno com o vetor em testVectorizerArray."
Aqui está o resultado:
fonte
transformer.fit
operações etfidf.todense()
? Você obteve seus valores de similaridade do loop e continuou fazendo tfidf? Onde seu valor cosseno calculado é usado? Seu exemplo é confuso.0.408
e0.816
quais são esses valores?Eu sei que é um post antigo. mas tentei o pacote http://scikit-learn.sourceforge.net/stable/ . aqui está meu código para encontrar a similaridade do cosseno. A questão era como você vai calcular a similaridade de cosseno com este pacote e aqui está o meu código para isso
Aqui, suponha que a consulta seja o primeiro elemento de train_set e doc1, doc2 e doc3 são os documentos que desejo classificar com a ajuda da similaridade de cosseno. então posso usar este código.
Além disso, os tutoriais fornecidos na questão foram muito úteis. Aqui estão todas as partes, parte-I , parte-II , parte-III
a saída será a seguinte:
aqui, 1 representa que a consulta é correspondida com ela mesma e os outros três são as pontuações para combinar a consulta com os respectivos documentos.
fonte
ValueError: Incompatible dimension for X and Y matrices: X.shape[1] == 1664 while Y.shape[1] == 2
Deixe-me dar outro tutorial escrito por mim. Ele responde à sua pergunta, mas também explica por que estamos fazendo algumas das coisas. Também tentei ser conciso.
Então você tem um
list_of_documents
que é apenas um array de strings e outrodocument
que é apenas um string. Você precisa encontrar esse documento nolist_of_documents
que é mais semelhante adocument
.Vamos combiná-los:
documents = list_of_documents + [document]
Vamos começar com dependências. Ficará claro por que usamos cada um deles.
Uma das abordagens que pode ser usada é um saco de palavras , em que tratamos cada palavra no documento independentemente das outras e apenas jogamos todas juntas no saco grande. De um ponto de vista, ele perde muitas informações (como como as palavras são conectadas), mas de outro ponto de vista, torna o modelo simples.
Em inglês e em qualquer outra língua humana, existem muitas palavras "inúteis" como 'a', 'the', 'in', que são tão comuns que não possuem muito significado. Eles são chamados de palavras de interrupção e é uma boa ideia removê-los. Outra coisa que se pode notar é que palavras como 'analisar', 'analisador', 'análise' são muito semelhantes. Eles têm uma raiz comum e todos podem ser convertidos em apenas uma palavra. Esse processo é chamado de stemming e existem diferentes stemmers que diferem em velocidade, agressividade e assim por diante. Assim, transformamos cada um dos documentos em uma lista de radicais de palavras sem palavras de interrupção. Também descartamos toda a pontuação.
Então, como esse saco de palavras nos ajudará? Imagine que temos 3 sacos:
[a, b, c]
,[a, c, a]
e[b, c, d]
. Podemos convertê-los em vetores na base[a, b, c, d]
. Então vamos acabar com vetores:[1, 1, 1, 0]
,[2, 0, 1, 0]
e[0, 1, 1, 1]
. O mesmo acontece com os nossos documentos (apenas os vetores serão muito mais longos). Agora vemos que removemos muitas palavras e originamos outras também para diminuir as dimensões dos vetores. Aqui há apenas uma observação interessante. Documentos mais longos terão muito mais elementos positivos do que mais curtos, por isso é bom normalizar o vetor. Isso é chamado de frequência de termo TF, as pessoas também usaram informações adicionais sobre a frequência com que a palavra é usada em outros documentos - IDF de frequência de documento inversa. Juntos, temos uma métrica TF-IDF que tem alguns sabores. Isso pode ser alcançado com uma linha em sklearn :-)Na verdade, o vetorizador permite fazer várias coisas, como remover palavras de interrupção e letras minúsculas. Eu as fiz em uma etapa separada apenas porque sklearn não tem palavras irrelevantes que não sejam em inglês, mas nltk tem.
Portanto, temos todos os vetores calculados. A última etapa é descobrir qual é o mais semelhante ao último. Existem várias maneiras de se conseguir isso, uma delas é a distância euclidiana que não é tão grande pelo motivo discutido aqui . Outra abordagem é a similaridade do cosseno . Nós iteramos todos os documentos e calculamos a similaridade de cosseno entre o documento e o último:
Agora o mínimo terá informações sobre o melhor documento e sua pontuação.
fonte
Isso deve ajudá-lo.
e a saída será:
fonte
Esta é uma função que compara seus dados de teste com os dados de treinamento, com o transformador Tf-Idf equipado com os dados de treinamento. A vantagem é que você pode rapidamente girar ou agrupar para encontrar os n elementos mais próximos e que os cálculos são feitos em termos de matriz.
fonte