文档过滤之“过滤博客订阅源”

过滤博客订阅源(Filtering Blog Feeds)

为了在真实环境下试验分类器,也为了演示其不同的用途,我们可以将分类器应用于来自某个博客或RSS订阅源的内容项。为此,我们需要用到曾在第3章中介绍过的 Universal Feed Parser。如果你还没有下载相应的函数库,则可以通过访问http://feedparser.org进行下载。有关安装Feed Parser的更多信息请见附录A。

尽管博客的内容中未必会包含垃圾信息,但是在众多博客所包含的文章中,并非所有的文章都是我们感兴趣的。这也许是因为我们只希望阅读属于某个分类的文章,或者某位作者所撰写的文章,不过通常而言实际情况要比这更为复杂。同样地,我们也可以针对自己感兴趣和不感兴趣的内容定义一些专门的规则——也许我们阅读了一个有关小件装置(gadget)的博客,并且对其中包含单词“cell phone”的内容不感兴趣——但是,假如利用前面已经构造好的分类器来为我们得出上述这些规则,其所需的工作量相对而言会更少一些。

对一个RSS订阅源中的内容项进行分类的好处在于,假如我们使用了像Google Blog Search这样的博客搜索工具,那么就可以在订阅源的阅读器中对搜索的结果进行定制了。许多人以此来追踪产品和他们感兴趣的内容,甚至还包括他们自己的名字。但是我们会发现,试图利用流量来赚钱的垃圾博客和那些毫无价值的博客也有可能会出现在这些搜索结果当中。

尽管许多订阅源因为拥有的内容项太少而无法进行任何有效的训练,不过在本例中,我们还是可以根据自己的喜好来选择任何的订阅源。在这个特定的例子里,我们使用 Google Blog Search对单词“Python”进行搜索,其搜索结果都是RSS形式的。你可以从http: //kiwitobes.com/feeds/python_search.xml处下载到这些结果。

请新建一个名为feedfilter.py的文件,并加入下列代码:

import feedparser
import re

# 接受一个博客订阅源的URL文件名并对内容项进行分类
def read(feed,classifier):
  # 得到订阅源的内容项并遍历循环
  f=feedparser.parse(feed)
  for entry in f['entries']:
    print
    print '-----'
    # 将内容项打印输出
    print 'Title:     '+entry['title'].encode('utf-8')
    print 'Publisher: '+entry['publisher'].encode('utf-8')
    print
    print entry['summary'].encode('utf-8')

    # 将所有文本组合在一起,为分类器构建一个内容项
    fulltext='%s\n%s\n%s' % (entry['title'],entry['publisher'],entry['summary'])

    # 将当前分类的最佳推测结果打印输出
    print 'Guess: '+str(classifier.classify(fulltext))

    # 请求用户给出正确分类,并据此进行训练
    cl=raw_input('Enter category: ')
    classifier.train(fulltext,cl)

该函数循环遍历所有内容项,并利用分类器得到有关分类的最佳推测结果。它向用户给出最佳推测,并接着询问正确的分类是什么。当我们使用一个新的分类器运行该程序时,起初的推测结果将会带有随机性,但是它们会随着时间的推移逐步得到改善。

上述构建好的分类器是完全通用的。尽管我们利用了垃圾信息过滤的例子来帮助说明每段代码的工作原理,但是分类的类别则可以是任何形式的内容。如果你正在使用python_search.xml,那么其中也许包含了4个分类——一个是关于编程语言的,一个是关于电影《Monty Python》的,一个是关于蟒蛇的,还有一个则是涉及任何其他内容的。请在你的Python会话中试着运行一下这个交互式的过滤器,设置好一个分类器,并将其传给feedfilter:

>>> import feedfilter
>>> cl=docclass.fisherclassifier(docclass.getwords)
>>> cl.setdb('python_feed.db')  # 仅当你使用的是SQLite
>>> feedfilter.read('python_search.xml',cl)

-----
Title:       My new baby boy!
Publisher: Shetan Noir, the zombie belly dancer! - MySpace Blog

This is my new baby, Anthem. He is a 3 and half month old ball <b>python</b>,
orange shaded normal pattern. I have held him about 5 times since I brought him
home tonight at 8:00pm...
Guess: None
Enter category: snake

-----
Title:      If you need a laugh...
Publisher: Kate's space

Even does 'funny walks' from Monty <b>Python</b>. He talks about all the ol'
Guess: snake
Enter category: monty

-----
Title:       And another one checked off the list..New pix comment ppl
Publisher: And Python Guru - MySpace Blog

Now the one of a kind NERD bred Carplot male is in our possesion. His name is Broken
(not because he is sterile) lol But check out the pic and leave one
Guess: snake
Enter category: snake

我们会发现,推测的结果随着时间的推移在逐渐的改善。由于没有太多有关于蛇的样本信息,尤其是它们被进一步划分成了宠物蛇和时尚一类的帖子,因此分类器对于这一分类的推测结果时常是错误的。当执行完整个训练之后,我们就可以得到针对于指定特征的概率值了——包括针对给定分类的单词概率,以及针对给定单词的分类概率:

>>> cl.cprob('python','prog')
0.33333333333333331
>>> cl.cprob('python','snake')
0.33333333333333331
>>> cl.cprob('python','monty')
0.33333333333333331
>>> cl.cprob('eric','monty')
1.0
>>> cl.fprob('eric','monty')
0.25

从上述结果中我们可以看到,由于每个内容项都包含单词“python”,因此该单词的概率被等分了。在涉及《Monty Python》的内容项中,有25%的文章包含了单词“Eric”,而其他内容项中则没有出现该单词。因此就“Eric”而言,对于给定分类的单词概率为 0.25,而对于给定单词的分类概率则为1.0。

本文节选自《集体智慧编程》第6章第8节“过滤博客订阅源”

posted @ 2009-03-27 13:34  博文视点  阅读(335)  评论(0编辑  收藏  举报