几个月前,我下载了数千篇计算机科学论文的元数据,这样我就可以尝试编写一个迷你推荐引擎来告诉我接下来应该读什么论文。
由于我没有任何人可以阅读每篇论文的数据,因此排除了协作过滤方法,所以我认为我可以尝试基于内容的过滤。
让我们快速检查一下基于内容过滤的Wikipedia定义 :
在基于内容的推荐器系统中,关键字用于描述项目,并且用户配置文件用于指示该用户喜欢的项目类型。
换句话说,这些算法试图推荐与用户过去喜欢(或正在检查)的商品相似的商品。
我们将重点放在查找算法的相似项部分上,并根据它们的标题来计算项的相似度,从而从简单开始。 如果我们使用论文的全文或至少使用摘要,则可能会得到更好的结果,但是数据不那么可用。
我们将采用以下方法来计算任意两对论文之间的相似性:
for each paper:
generate a TF/IDF vector of the terms in the paper's title
calculate the cosine similarity of each paper's TF/IDF vector with every other paper's TF/IDF vector
使用Python scikit-learn库非常容易做到这一点,而我实际上已经完成了过程的第一部分,同时对电视节目《我如何与母亲见面》中的有趣短语进行了一些探索性分析 。
让我们开始吧。
每篇论文只有一个文件,其中包含论文的标题。 我们首先需要遍历该目录并构建一个包含论文的数组:
import glob
corpus = []
for file in glob.glob("papers/*.txt"):
with open(file, "r") as paper:
corpus.append((file, paper.read()))
接下来,我们将为每篇论文构建一个TF / IDF矩阵:
from sklearn.feature_extraction.text import TfidfVectorizer
tf = TfidfVectorizer(analyzer='word', ngram_range=(1,3), min_df = 0, stop_words = 'english')
tfidf_matrix = tf.fit_transform([content for file, content in corpus])
接下来,我们将编写一个函数,该函数将基于余弦相似度为我们找到前n个相似的论文:
from sklearn.metrics.pairwise import linear_kernel
def find_similar(tfidf_matrix, index, top_n = 5):
cosine_similarities = linear_kernel(tfidf_matrix[index:index+1], tfidf_matrix).flatten()
related_docs_indices = [i for i in cosine_similarities.argsort()[::-1] if i != index]
return [(index, cosine_similarities[index]) for index in related_docs_indices][0:top_n]
让我们尝试一下:
>>> corpus[1619]
('papers/221215.txt', 'TOTEM: a reliable ordered delivery protocol for interconnected local-area networks')
>>> for index, score in find_similar(tfidf_matrix, 1619):
print score, corpus[index]
0.917540397202 ('papers/852338.txt', 'A reliable ordered delivery protocol for interconnected local area networks')
0.248736845733 ('papers/800897.txt', 'Interconnection of broadband local area networks')
0.207309089025 ('papers/103726.txt', 'High-speed local area networks and their performance: a survey')
0.204166719869 ('papers/161736.txt', 'High-speed switch scheduling for local-area networks')
0.198514433132 ('papers/627363.txt', 'Algorithms for Distributed Query Processing in Broadcast Local Area Networks')
查找重复的论文非常好!
>>> corpus[1599]
('papers/217470.txt', 'A reliable multicast framework for light-weight sessions and application level framing')
>>> for index, score in find_similar(tfidf_matrix, 1599):
print score, corpus[index]
1.0 ('papers/270863.txt', 'A reliable multicast framework for light-weight sessions and application level framing')
0.139643354066 ('papers/218325.txt', 'The KryptoKnight family of light-weight protocols for authentication and key distribution')
0.134763799612 ('papers/1251445.txt', 'ALMI: an application level multicast infrastructure')
0.117630311817 ('papers/125160.txt', 'Ordered and reliable multicast communication')
0.117630311817 ('papers/128741.txt', 'Ordered and reliable multicast communication')
但是有时它会标识不相同的重复项:
>>> corpus[5784]
('papers/RFC2616.txt', 'Hypertext Transfer Protocol -- HTTP/1.1')
>>> for index, score in find_similar(tfidf_matrix, 5784):
print score, corpus[index]
1.0 ('papers/RFC1945.txt', 'Hypertext Transfer Protocol -- HTTP/1.0')
1.0 ('papers/RFC2068.txt', 'Hypertext Transfer Protocol -- HTTP/1.1')
0.232865694216 ('papers/131844.txt', 'XTP: the Xpress Transfer Protocol')
0.138876842331 ('papers/RFC1866.txt', 'Hypertext Markup Language - 2.0')
0.104775586915 ('papers/760249.txt', 'On the transfer of control between contexts')
话虽如此,如果您正在阅读并喜欢HTTP 1.0 RFC,那么HTTP 1.1 RFC可能不是一个不错的建议。
显然,也有一些论文被认为是相似的,而并非相似。 我创建了一个CSV文件 ,每张纸包含5张相似的纸,只要相似度大于0.5。 您也可以在github上看到生成该文件的脚本 。
到目前为止,我已经了解了很多,但接下来我将要探讨以下几件事:
- 我们如何知道相似性建议是否有用? 我们如何衡量好? 使用术语计数向量比TF / IDF更好吗?
- 基于摘要和/或标题的相似性
这篇文章中所有用于计算相似性并将其写入CSV的代码也位于github上,因此可以随意使用。