推荐相关文章的可靠算法都有哪些?
Posted
技术标签:
【中文标题】推荐相关文章的可靠算法都有哪些?【英文标题】:What tried and true algorithms for suggesting related articles are out there?推荐相关文章的可靠算法有哪些? 【发布时间】:2010-11-18 06:50:06 【问题描述】:很常见的情况,我敢打赌。你有一个博客或新闻网站,你有很多文章或博客或任何你称之为的东西,你想在每一个的底部推荐其他似乎相关的内容。
让我们假设每个项目的元数据很少。也就是说,没有标签、类别。视为一大块文本,包括标题和作者姓名。
你如何寻找可能相关的文件?
我对实际算法很感兴趣,而不是现成的解决方案,尽管我可以看看用 ruby 或 python 实现的东西,或者依赖 mysql 或 pgsql。
编辑:目前的答案非常好,但我希望看到更多。也许是一两件事的一些非常简单的示例代码。
【问题讨论】:
我变成了一个糟糕的标注员。非常欢迎标签编辑。 查看竞赛.github.com 以获取针对类似问题的大量开源解决方案。 好了,添加了完整的 Ruby 示例。 【参考方案1】:这是一个相当大的话题——除了人们在这里提出的答案之外,我建议跟踪几个信息检索课程的教学大纲,并查看分配给他们的教科书和论文。也就是说,以下是我自己研究生时代的简要概述:
最简单的方法称为bag of words。每个文档都被简化为 word: wordcount
对的稀疏向量,您可以在表示您的文档集的向量集上扔一个 NaiveeBayes(或其他一些)分类器,或者计算每个袋子和每个其他袋子之间的相似度分数(这称为k-最近邻分类)。 KNN 查找速度很快,但得分矩阵需要 O(n^2) 存储;但是,对于博客来说,n 并不是很大。对于大型报纸大小的东西,KNN 很快变得不切实际,因此动态分类算法有时会更好。在这种情况下,您可以考虑使用ranking support vector machine。 SVM 很简洁,因为它们不会限制您使用线性相似性度量,并且仍然非常快。
Stemming 是词袋技术的常用预处理步骤;这涉及在计算词袋之前将形态相关的词(例如“cat”和“cats”、“Bob”和“Bob's”或“similar”和“similarly”)减少到它们的根。有很多不同的词干算法。***页面有几个实现的链接。
如果词袋相似度不够好,您可以将其抽象为 N-gram 袋相似度的层,在该层中,您可以根据词对或词组创建表示文档的向量。 (您可以使用 4 元组甚至更大的元组,但实际上这并没有多大帮助。)这具有产生更大向量的缺点,因此分类将花费更多工作,但您获得的匹配会更接近在句法上。 OTOH,您可能不需要这个语义相似性;它更适合剽窃检测之类的东西。 Chunking,或者将文档简化为轻量级解析树,也可以使用(有树的分类算法),但这对于作者问题(“给定一个来源不明的文档,谁写的)更有用?”)。
也许对您的用例更有用的是概念挖掘,它涉及将单词映射到概念(使用诸如WordNet 之类的同义词库),然后根据所用概念之间的相似性对文档进行分类。这通常比基于词的相似度分类更有效,因为从词到概念的映射是简化的,但预处理步骤可能相当耗时。
最后是discourse parsing,它涉及解析文档的语义结构;您可以像在分块文档上一样在话语树上运行相似性分类器。
这些几乎都涉及从非结构化文本生成元数据;在原始文本块之间进行直接比较是难以处理的,因此人们首先将文档预处理为元数据。
【讨论】:
这些有 C++ 库吗?另外,这些信息是否仍然是最新的。【参考方案2】:前段时间我实现了类似的东西。也许这个想法现在已经过时了,但我希望它能有所帮助。
我运行了一个 ASP 3.0 网站来编写常见任务,并从这个原则开始:用户有疑问,只要他/她能找到关于该主题的有趣内容,他/她就会留在网站上。
当用户到达时,我启动了一个 ASP 3.0 Session
对象并记录了所有用户导航,就像一个链表一样。在Session.OnEnd
事件中,我获取第一个链接,查找下一个链接并增加一个计数器列,例如:
<Article Title="Cookie problem A">
<NextPage Title="Cookie problem B" Count="5" />
<NextPage Title="Cookie problem C" Count="2" />
</Article>
因此,要查看相关文章,我只需列出顶部 n NextPage
实体,按计数器列降序排列。
【讨论】:
【参考方案3】:这是Document Classification 的典型案例,在机器学习的每一堂课中都有研究。如果你喜欢统计学、数学和计算机科学,我建议你看看像kmeans++、Bayesian methods 和LDA 这样的无监督方法。特别是,贝叶斯方法是 pretty good 在您正在寻找的东西上,它们唯一的问题是速度很慢(但除非您运行一个非常大的网站,否则这不会给您带来太多麻烦)。
在一个更实用、更少理论的方法上,我建议你看看 this 和 this other 很棒的代码示例。
【讨论】:
实际上,我认为这比“文档分类”的正常定义要严格得多。之所以?你正试图击中一个移动的目标!您的课程是由您正在阅读的文本定义的,而不是由诸如“垃圾邮件”或“代码”或“英语”之类的预定义类定义【参考方案4】:Ruby 中的小型向量空间模型搜索引擎。基本思想是如果两个文档包含相同的单词,则它们是相关的。所以我们计算每个文档中单词的出现次数,然后计算这些向量之间的余弦(每个词都有一个固定的索引,如果它出现在该索引处有一个 1,如果不是零)。如果两个文档的所有术语都相同,则余弦值为 1.0,如果它们没有共同术语,则余弦值为 0.0。您可以直接将其转换为 % 值。
terms = Hash.new|h,k|h[k]=h.size
docs = DATA.collect |line|
name = line.match(/^\d+/)
words = line.downcase.scan(/[a-z]+/)
vector = []
words.each |word| vector[terms[word]] = 1
:name=>name,:vector=>vector
current = docs.first # or any other
docs.sort_by |doc|
# assume we have defined cosine on arrays
doc[:vector].cosine(current[:vector])
related = docs[1..5].collect|doc|doc[:name]
puts related
__END__
0 Human machine interface for Lab ABC computer applications
1 A survey of user opinion of computer system response time
2 The EPS user interface management system
3 System and human system engineering testing of EPS
4 Relation of user-perceived response time to error measurement
5 The generation of random, binary, unordered trees
6 The intersection graph of paths in trees
7 Graph minors IV: Widths of trees and well-quasi-ordering
8 Graph minors: A survey
Array#cosine
的定义留给读者作为练习(应该处理 nil 值和不同的长度,但我们得到了Array#zip
对吗?)
顺便说一句,示例文档取自 Deerwester 等人的 SVD 论文 :)
【讨论】:
【参考方案5】:您应该阅读《编程集体智能:构建智能 Web 2.0 应用程序》(ISBN 0596529325)一书!
对于一些方法和代码:首先问问自己,是想根据单词匹配找到直接相似的地方,还是想展示可能与当前不直接相关但属于同一个聚类的相似文章文章。
见Cluster analysis / Partitional clustering。
找到直接相似性的一种非常简单(但理论上且缓慢)的方法是:
预处理:
-
存储每篇文章的平面单词列表(不要删除重复的单词)。
“交叉连接”文章:计算文章A中匹配文章B中相同单词的单词数。你现在有一个矩阵
int word_matches[narticles][narticles]
(你不应该这样存储它,A->B的相似性相同如 B->A,所以稀疏矩阵几乎节省了一半的空间)。
将 word_matches 计数标准化为范围 0..1! (找到最大计数,然后除以任何计数) - 你应该在那里存储浮点数,而不是整数;)
查找类似文章:
-
从 word_matches 中选择匹配度最高的 X 篇文章
【讨论】:
以上是关于推荐相关文章的可靠算法都有哪些?的主要内容,如果未能解决你的问题,请参考以下文章