什么尝试和真正的算法建议相关的文章在那里?

时间:2009-08-10 12:38:21

标签: text machine-learning information-retrieval document-classification

很常见的情况,我打赌。你有一个博客或新闻网站,你有很多文章或错误或任何你称之为的东西,你想在每个网站的底部建议其他似乎相关的内容。

让我们假设每个项目的元数据非常少。也就是说,没有标签,类别。视为一大块文本,包括标题和作者姓名。

你如何找到可能相关的文件?

我对实际算法很感兴趣,而不是现成的解决方案,虽然我可以看看在ruby或python中实现的东西,或者依赖于mysql或pgsql。

编辑:目前的答案相当不错,但我想看到更多。对于一两件事,可能有一些非常简单的示例代码。

5 个答案:

答案 0 :(得分:38)

这是一个非常大的话题 - 除了人们在这里提出的答案之外,我建议您查看一些信息检索课程的教学大纲,并查看分配给他们的教科书和论文。也就是说,这是我自己的研究生日的简要概述:

最简单的方法称为bag of words。每个文档都缩减为{word: wordcount}对的稀疏向量,您可以将NaiveBayes(或其他一些)分类器放在代表您的文档集的向量集上,或者计算每个包之间的相似度得分。 bag(这称为k-最近邻分类)。 KNN快速查找,但需要O(n ^ 2)存储分数矩阵;但是,对于博客来说,n不是很大。对于大型报纸大小的东西,KNN迅速变得不切实际,因此动态分类算法有时会更好。在这种情况下,您可以考虑ranking support vector machine。 SVM很整洁,因为它们不会限制您使用线性相似性度量,并且仍然非常快。

Stemming是词袋技术的常见预处理步骤;这涉及在计算单词包之前减少与形态相关的单词,例如“猫”和“猫”,“鲍勃”和“鲍勃”,或“相似”和“类似”,直到它们的根。那里有许多不同的词干算法;维基百科页面包含多个实现的链接。

如果词袋相似性不够好,您可以将它抽象为一层N-gram相似度,您可以在其中创建基于词对或三元组表示文档的向量。 (你可以使用4元组甚至更大的元组,但在实践中这没有多大帮助。)这样做的缺点是产生更大的矢量,因此分类会花费更多的工作,但你得到的匹配会更接近语法。 OTOH,你可能不需要这个用于语义相似性;对抄袭检测这样的东西更好。也可以使用Chunking,或者将文档缩减为轻量级解析树(对于树有分类算法),但这对于作者身份问题更有用(“给出一个来历不明的文档,谁写了吗?“)。

对您的用例可能更有用的是概念挖掘,其涉及将单词映射到概念(使用诸如WordNet的词库),然后基于所使用的概念之间的相似性对文档进行分类。这通常比基于单词的相似性分类更有效,因为从单词到概念的映射是还原性的,但预处理步骤可能相当耗时。

最后,有discourse parsing,它涉及解析文档的语义结构;你可以在语篇树上运行相似性分类器,就像在分块文档上一样。

这几乎涉及从非结构化文本生成元数据;在原始文本块之间进行直接比较是难以处理的,因此人们首先将文档预处理为元数据。

答案 1 :(得分:4)

这是Document Classification的典型案例,在每一类机器学习中进行了研究。如果您喜欢统计学,数学和计算机科学,我建议您查看kmeans++Bayesian methodsLDA等无监督方法。特别是贝叶斯方法pretty good在你想要的是什么,他们唯一的问题是缓慢(但除非你运行一个非常大的网站,这不应该打扰你)。

关于更实际且理论上更少理论的方法,我建议您查看thisthis other个很棒的代码示例。

答案 2 :(得分:4)

您应该阅读“编程集体智慧:构建智能Web 2.0应用程序”一书(ISBN 0596529325)!

对于某些方法和代码:首先问问自己,是否要根据单词匹配找到直接相似性,或者是否要显示可能与当前文章不直接相关的类似文章,但属于同一个集群制品

请参阅Cluster analysis / Partitional clustering

找到直接相似性的一种非常简单(但理论和缓慢)的方法是:

预处理:

  1. 每篇文章存储单词单词列表(不要删除重复的单词)。
  2. “交叉加入”文章:计算文章A中与文章B中相同单词匹配的单词数量。您现在有一个矩阵int word_matches[narticles][narticles](您不应该像那样存储它,A->的相似性; B与B-> A相同,因此稀疏矩阵节省了几乎一半的空间。
  3. 将word_matches计数标准化为范围0..1! (找到最大计数,然后用此除以任何计数) - 你应该在那里存储浮点数,而不是整数;)
  4. 查找类似文章:

    1. 从word_matches
    2. 中选择匹配率最高的X篇文章

答案 3 :(得分:3)

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对吧?)

BTW,示例文件取自Deerwester等人的SVD论文:)

答案 4 :(得分:1)

前段时间我实现了类似的东西。也许这个想法现在已经过时了,但我希望它可以提供帮助。

我运行了一个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实体,按计数器列降序排序。