聚类算法(1)

聚类是的无监督学习一个例子。无监督学习与监督学习最显著的不同在于,无监督学习寻找的并不是一些什么数据,而是一种模式,或规律,或者,聚类

 

比如,我们要对一系列博客进行聚类以从中发现一些规律(《Programming Collective Intelligence》),我们主要根据单词频度来对博客进行聚类。

 

构造数据

我们使用feedparser对博客的RSS订阅源进行解析,以得到相关的单词频度。

 

以下函数从一个订阅源得到一单词频度列表。

 

关于d.entries:

entries实际是有好些项的,所以这里可以写作d.entries[i]

注意这里的一句话:“This element always exists, although it may be an empty list.”。实际上,entries可能为空,所以在使用之前我们应该对其进行判断。判断方法有两种,一种是用len,一中是用not。另,e.summary和e.description是相等的。e.titled.feed.title是不同的,前者是某条条目的title,即是某篇文章的标题,后者是这个博客的title。

 

所调用的getwords如下:

 

说明:1.关于html标记。(去掉的是那些html标记的符号,标记的具体内容并没有去掉)

         2.关于re

 

main code:

 

这里的流程如下:

1.将所有url从文件feedlist.txt(文件名etc可换)读入到feedlist

2.解析每个url,将其名字和该博客中的单词计数列表存入tilte和wc中。将博客题目和其中所有不同单词出现的次数保存至wordcounts

3.统计出现某单词的博客数目,存入apcount(单词,出现于的博客数)中。前提是,如果该单词在该博客中出现过1次或一次以上,则将apcount[word]加1

4.因为很多单词,比如the,a之类的,几乎出现在每篇博文中,因此,我们对出现的单词进行频率限制。低于10%或高于50%的都舍弃。其余存入wordlist中。

5.新建文件blogdata.txt,写入相关数据。(包括,经频率限制处理过的单词,写入每个博客中所出现的经过频率限制处理的单词的次数)

所写blogdata.txt片段如下(数据经过裁剪,个数不一定相对应):

 

那么如何实现按主题分类博客呢?可以采用分级聚类的方法。

 

 

分级聚类

分级聚类通过连续不断的将最为相似(两元素之间的距离最近)的群组两两合并,构造一个群组的层级结构。分级结构最终形成树状图。树状图可以有效的确定图中个元素的相似程度。

 

因此在此例中,要实现按主题队博客分类,只需要构造博客的分级聚类,若构造成功,则可对博客进行聚类。

 

读入数据

首先从我们写成的blogdata.txt中读入数据。

 

要强烈的注意下blogdata的格式,如下:

第一行:Blog xxx xxx xxx xxx (xxx为出现在各博客中的合理单词)

第二行:blogname 000 000 000 000 (000为第一行中各个单词在博客blogname中出现的次数,可能为0次)

........  .......(同第二行)

函数readfile中的列标题即是那些合理单词;行名即是博客名字;data即是该单词出现在各博客中的次数。

 

聚类算法

算法hcluster完成对以上data的聚类功能。

 

初始时,每个单独的行均构成一个聚类,随之程序对每两行之间的距离进行计算并进行聚类操作,直至只有1行存在(while len(clust) > 1:),即只有一个聚类。

整个算法是个无敌的三重循环。。。

while中的双重for是遍历整个聚类寻找距离最小的二聚类。为加快运行,对两个聚类直接的距离值进行了缓存,因为,在这两类不合并或不和其他类合并之前,其离都是相等的,计算结果保存在distances中,其结果大致为:distances == {(聚类1,聚类2):距离},所以在存入distances或从中取值时,我们使用的key是元组,该元组是聚类的id(每个聚类均有唯一的id,这是clust = [bicluster(rows[i], id=i) for i in range(len(rows))]的功劳。。。)。

 

记住我们所计算的是什么的聚类?

我们的目标是,找出相似的博客。我们通过聚类来达到这一点的。我们计算的是,关于某博客中出现的所有单词的频度的聚类。以此我们将所有的博客根据其中出现的单词的情况进行聚类(做成树状图)。

 

在找到了两个聚类后,我们对其中的所有单词频度求平均,并以此作为新的聚类,参与下一次的寻找。

 

求距离我们使用经典的皮尔逊算法

 

该算法返回的是0~1之间的数字。完全匹配返回1,否则返回0.即是说,相距越近,则返回的数字越大;但我们的算中是返回的:1.0-num/den,即相距越近则返回数字越小。这与我们的常识是相同的,注意对此算法hcluster中的判断条件是if d < closest,而不是>。

 

嗯,还可以。。。

把这棵树画出来看看?

 

树状图

使用PIL来画树状图。

 

参数选择很重要,尤其是当数据很多时,否则画出来的将会惨不忍睹。。。

上面这段画树的代码来自《Programming Collective Intelligence》。每个语言都有其相应的库/框架之类,但仿佛Python特别多,而且特别杂特别神,比如传说的用Python操作MS Office的xlrd,xlwt之类。但我们只是用而已,而且做树状图对聚类算法来说并非是必要的一步,因此对以上代码没有精研。。。(我该补一句:详情请参考用户手册。。。)

 

 

列聚类

我们上面提到过,说,我们所要进行的是,对博客,依据其中所使用的单词,进行聚类,这样就把相似的博客聚合在了一起。在上面的例子中,我们聚类所操作的,实际上是行,行即是博客的名字。

那列呢?列是什么?

列是单词。如果我们对单词进行聚类呢?那么,我们可以看出哪些单词可能被同时使用,哪些不太可能被同时使用,这就是列聚类(如果商店使用列聚类算法得出哪些商品用户经常同时购买,那么就能很方便的进行捆绑销售了。。。)。。。

 

我们上面所进行的是行聚类,在行聚类中,行是博客列是单词;如果要进行列聚类又要直接使用上面的算法,那么最好的办法(也是最简单的办法)就是,将上面的数据进行反置,使,行代表单词,列代表次数。

 

 

 

我们上面的格式是:

 

第一行:Blog xxx xxx xxx xxx (xxx为出现在各博客中的合理单词)

第二行:blogname 000 000 000 000 (000为第一行中各个单词在博客blogname中出现的次数,可能为0次)

........  .......(同第二行)

那么我们更改后的格式如:

 

第一行:Blog xxx xxx xxx xxx (xxx为出现在各博客)

第二行:单词 000 000 000 000 (000为该单词出现于列所代表的博客中的次数)

........  .......(同第二行)

 

 

总结行聚类和列聚类:

当数据项的数量比变量多的时候,出现无意义聚类的可能性就会增加。由于单词的数量比博客多得多,因此,在博客聚类中出现的模式要比在单词聚类中出现的更加合理。

 

 

总结分级聚类算法:

分级聚类将聚类表示成了直观的树状图。

两个缺点:

1.树状图并不会真正拆分数据,树状图只是表示出了该关系。(可以说,该关系并不能保存持久。。。)

2.结算量太过可观。。。

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值