使用 sklearn 如何计算文档和查询之间的 tf-idf 余弦相似度?

Using sklearn how do I calculate the tf-idf cosine similarity between documents and a query?

我的目标是输入 3 个查询并找出哪个查询与一组 5 个文档最相似。

到目前为止,我计算了执行以下操作的文档的 tf-idf

from sklearn.feature_extraction.text import TfidfVectorizer

def get_term_frequency_inverse_data_frequency(documents):
    allDocs = []
    for document in documents:
        allDocs.append(nlp.clean_tf_idf_text(document))
    vectorizer = TfidfVectorizer()
    matrix = vectorizer.fit_transform(allDocs)
    return matrix

def get_tf_idf_query_similarity(documents, query):
    tfidf = get_term_frequency_inverse_data_frequency(documents)

我遇到的问题是现在我有 tf-idf 个文档,我对查询执行什么操作才能找到与文档的余弦相似度?

余弦相似度是表示文档的向量之间夹角的余弦值。

K(X, Y) = <X, Y> / (||X||*||Y||)

您的 tf-idf 矩阵将是维度为 no 的稀疏矩阵。文件数量 * 没有。不同的词。

要打印整个矩阵,您可以使用 todense()

print(tfidf.todense())

每一行代表一个文档对应的向量表示。同样,每列对应于语料库中唯一单词的 tf-idf 分数。

向量和任何其他向量之间的成对相似性可以从 tf-idf 矩阵计算为:

from sklearn.metrics.pairwise import cosine_similarity
cosine_similarity(reference_vector, tfidf_matrix) 

输出将是一个长度为 no 的数组。文档表示您的参考向量和对应于每个文档的向量之间的相似性得分。当然参考向量和它自己的相似度会是1。总的来说它会是0到1之间的一个值。

要找到第一个和第二个文档之间的相似性,

print(cosine_similarity(tfidf_matrix[0], tfidf_matrix[1]))

array([[0.36651513]])

你可以按照 Nihal 在他的回复中写的那样做,或者你可以使用 sklearn 中的最近邻算法。您必须 select 正确的度量(余弦)

from sklearn.neighbors import NearestNeighbors
neigh = NearestNeighbors(n_neighbors=5, metric='cosine')

其他答案非常有帮助,但并不完全是我想要的,因为它们没有帮助我转换查询,因此我无法将其与文档进行比较。

为了转换查询,我首先将其拟合到文档矩阵:

queryTFIDF = TfidfVectorizer().fit(allDocs)

然后我将它转化为矩阵形状:

queryTFIDF = queryTFIDF.transform([query])

然后使用 sklearn.metrics.pairwise.cosine_similarity 函数

计算所有文档与我的查询之间的余弦相似度
cosineSimilarities = cosine_similarity(queryTFIDF, docTFIDF).flatten()

虽然我意识到使用 Nihal 的解决方案我可以将我的查询作为文档之一输入,然后计算它与其他文档之间的相似度,但这对我来说是最有效的。

完整代码最终看起来像:

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity

def get_tf_idf_query_similarity(documents, query):
    allDocs = []
    for document in documents:
        allDocs.append(nlp.clean_tf_idf_text(document))
    docTFIDF = TfidfVectorizer().fit_transform(allDocs)
    queryTFIDF = TfidfVectorizer().fit(allDocs)
    queryTFIDF = queryTFIDF.transform([query])

    cosineSimilarities = cosine_similarity(queryTFIDF, docTFIDF).flatten()
    return cosineSimilarities

这是我的建议:

  • 我们不必两次拟合模型。我们可以重用相同的矢量器
  • 文本清理功能可以直接使用 preprocessing 属性插入到 TfidfVectorizer 中。
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity

vectorizer = TfidfVectorizer(preprocessor=nlp.clean_tf_idf_text)
docs_tfidf = vectorizer.fit_transform(allDocs)

def get_tf_idf_query_similarity(vectorizer, docs_tfidf, query):
    """
    vectorizer: TfIdfVectorizer model
    docs_tfidf: tfidf vectors for all docs
    query: query doc

    return: cosine similarity between query and all docs
    """
    query_tfidf = vectorizer.transform([query])
    cosineSimilarities = cosine_similarity(query_tfidf, docs_tfidf).flatten()
    return cosineSimilarities