常见的方法是将文档转换为 TF-IDF 向量,然后计算它们之间的余弦相似度。任何有关信息检索 (IR) 的教科书都涵盖了这一点。参见特别是。信息检索简介 http://www-nlp.stanford.edu/IR-book/,这是免费且在线提供的。
计算成对相似度
TF-IDF(以及类似的文本转换)在 Python 包中实现Gensim http://radimrehurek.com/gensim/ and scikit学习 http://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.TfidfTransformer.html#sklearn.feature_extraction.text.TfidfTransformer。在后一个包中,计算余弦相似度就像
from sklearn.feature_extraction.text import TfidfVectorizer
documents = [open(f).read() for f in text_files]
tfidf = TfidfVectorizer().fit_transform(documents)
# no need to normalize, since Vectorizer will return normalized tf-idf
pairwise_similarity = tfidf * tfidf.T
或者,如果文档是纯字符串,
>>> corpus = ["I'd like an apple",
... "An apple a day keeps the doctor away",
... "Never compare an apple to an orange",
... "I prefer scikit-learn to Orange",
... "The scikit-learn docs are Orange and Blue"]
>>> vect = TfidfVectorizer(min_df=1, stop_words="english")
>>> tfidf = vect.fit_transform(corpus)
>>> pairwise_similarity = tfidf * tfidf.T
尽管 Gensim 对于此类任务可能有更多选择。
也可以看看这个问题 https://stackoverflow.com/questions/2380394/simple-implementation-of-n-gram-tf-idf-and-cosine-similarity-in-python.
[免责声明:我参与了 scikit-learn TF-IDF 的实现。]
解释结果
从上面,pairwise_similarity
是一个 Scipy稀疏矩阵 https://docs.scipy.org/doc/scipy/reference/sparse.html它是正方形的,行数和列数等于语料库中文档的数量。
>>> pairwise_similarity
<5x5 sparse matrix of type '<class 'numpy.float64'>'
with 17 stored elements in Compressed Sparse Row format>
您可以通过以下方式将稀疏数组转换为 NumPy 数组.toarray()
or .A
:
>>> pairwise_similarity.toarray()
array([[1. , 0.17668795, 0.27056873, 0. , 0. ],
[0.17668795, 1. , 0.15439436, 0. , 0. ],
[0.27056873, 0.15439436, 1. , 0.19635649, 0.16815247],
[0. , 0. , 0.19635649, 1. , 0.54499756],
[0. , 0. , 0.16815247, 0.54499756, 1. ]])
假设我们想要找到与最终文档“The scikit-learn docs are Orange and Blue”最相似的文档。该文档的索引 4 位于corpus
。您可以通过以下方式找到最相似文档的索引获取该行的 argmax,但首先您需要屏蔽 1,它表示每个文档与其自身的相似度。您可以通过执行后者np.fill_diagonal()
,而前者通过np.nanargmax()
:
>>> import numpy as np
>>> arr = pairwise_similarity.toarray()
>>> np.fill_diagonal(arr, np.nan)
>>> input_doc = "The scikit-learn docs are Orange and Blue"
>>> input_idx = corpus.index(input_doc)
>>> input_idx
4
>>> result_idx = np.nanargmax(arr[input_idx])
>>> corpus[result_idx]
'I prefer scikit-learn to Orange'
注意:使用稀疏矩阵的目的是为大型语料库和词汇表节省(大量空间)。您可以执行以下操作,而不是转换为 NumPy 数组:
>>> n, _ = pairwise_similarity.shape
>>> pairwise_similarity[np.arange(n), np.arange(n)] = -1.0
>>> pairwise_similarity[input_idx].argmax()
3