集体智慧学习编程——自我改编应用

学习目标:

1、利用博客资源自我创建数据集;

2、利用皮尔逊相关度描述单个数据之间的紧密度;

3、对从新浪博客爬取的博客进行分类;

4、绘制树状图。


一、利用博客资源创建数据集:

我这里选取的是新浪博客,例如http://roll.finance.sina.com.cn/blog/blogarticle/cj-bkks/inde_1.shtml, 其中url中数字1是页码。基于这个规律,可以抓取很多很多博客来充实数据集。

为了实现博客的抓取,这里我写了一个小爬虫,因为这不是学习的重点,这里就直接上代码了,我都写了注释的:

注意,我的运行环境是python2.7.

[python]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. # -*- coding: utf-8 -*-  
  2. import urllib  
  3. from bs4 import BeautifulSoup  
  4. import codecs  
  5. import jieba  
  6. from collections import Counter  
  7.   
  8. #获取当页所有博客的url,以list的方式返回  
  9. def get_all_urls(url):  
  10.     content = urllib.urlopen(url).read()  
  11.     soup = BeautifulSoup(content, 'lxml')   #利用beautifsoup进行html的解析  
  12.     url_list = list()  
  13.     for item in soup.find_all('ul'class_ = 'list_009'):  
  14.         for i in item.find_all('li'): url_list.append(i.a['href'])  
  15.     return url_list  
  16.   
  17. #输入博客的url,返回博客内容  
  18. def get_content(url):  
  19.     text = urllib.urlopen(url).read()  
  20.     soup = BeautifulSoup(text, 'lxml')  
  21.     content = soup.find('div'class_ = 'articalContent').get_text()  
  22.     return content  
  23.       
  24.   
  25. words_list = list()   #标记词列表  
  26. dd = dict()  
  27. for i in range(120):  
  28.     page = 'http://roll.finance.sina.com.cn/blog/blogarticle/cj-bkks/inde_' + str(i) + '.shtml'  
  29.     url_list = get_all_urls(page)  
  30.     for i in range(len(url_list)):  
  31.         url = url_list[i]  
  32.         content = get_content(url).strip()  
  33.         filename = str(i) + '.txt'  
  34.         file = codecs.open(filename, 'w', encoding = 'utf-8')       #打开文档文件,存入每一篇博客内容  
  35.         file.write(content)  
  36.         file.close  
  37.         for words in jieba.cut(content, cut_all = False):   #利用结巴分词,对中文分词,获取标记词列表  
  38.             words_list.append(words)  
  39.         print i  
  40.         i = i + 1  
  41.   
  42. d = Counter(words_list)         #对标记词列表中进行统计处理,Counter返回一个字典,key是标记词,value是出现的次数  
  43. l = list()                      #对字典进行‘排序’  
  44. for k,v in d.items():  
  45.     l.append((v,k))  
  46. l.sort(reverse = True)  
  47. file = codecs.open('frequency.txt''w', encoding = 'utf-8')  
  48. for item in l:  
  49.     if item[0] > 4 and item[0] < 80:        #去除出现频率过高或者过低的词,可以自己改动了。最后存入frequency.txt文档  
  50.         file.write(item[1] + '\r\n')  

此时在你Python程序运行的文件夹中就会出现很多txt文本文件:



二、利用皮尔逊相关度描述单个数据之间的紧密度:

一般用欧几里德距离和皮尔逊相关度来评价数据之间的相似程度,或者是紧密度。相比较而言,欧几里德距离更加直观,因此一般而言也采用的更多一点,如果是比较简单的情况下。但是这里我采用的是后者,因为可能会有些博客字数较少(很多),使得这些博客包含更少(更多)的词汇,这样使得欧几里德距离会很大。皮尔逊相关法从直观的意义上来讲,是两数据拟合直线的比较,数据点更多只是意味着拟合直线更加精确,因此可以很好的纠正这种误差。这里代表每篇博客的特征是一个对标记词统计后的list。

这里贴出皮尔逊相关法的代码:(http://lobert.iteye.com/blog/2024999,大家也可以看看这篇文章)

[python]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. def distance(item1, item2):  
  2.     sum1 = sum(item1)  
  3.     sum2 = sum(item2)  
  4.       
  5.     sum1sq = sum([pow(v, 2for v in item1])  
  6.     sum2sq = sum([pow(v, 2for v in item2])  
  7.     psum = sum([item1[i] * item2[i] for i in range(len(item1))])  
  8.       
  9.     num = psum - (sum1 *sum2 / len(item1))  
  10.     den = sqrt(sum1sq - pow(sum1, 2)/len(item1)) * (sum2sq - pow(sum2, 2)/ len(item1))  
  11.     if den == 0 : return 0  
  12.     elsereturn 1 - num/den      
[python]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1.   

三、对从新浪博客爬取的博客进行分类:

我们现在已经获得了标记词、每篇博客的内容以及评价博客之间相关关系的方法,接下来我们就来对博客进行分级聚类。

分级聚类是通过不断将最相似的群组两两合并,来构造出一个群组的层级结构,如下图:

因为我们是对博客进行分类,这里把上图中的A,B,C,D,E看成是5篇博客。首先利用皮尔逊相关度来两两评价博客之间的紧密度,然后找出紧密度最小的两篇博客,这里是AB。将AB博客的特性list合并(相加求平均值),组成一个新“博客”,然后对AB,C,D,E一共4篇博客两两计算紧密度,找出紧密度最小的一组博客。重复上述过程,直至将所有博客聚类成一组。对上述最终结果进行可视化处理,即可用树状图来表示:


树状图可以非常直观地来显示我们分级聚类的结果。节点间的距离代表了之间的紧密度。如:d1是节点1与A、B的距离;d2是节点3与D、E之间的距离。虽然节点1和节点2都仅有一个分支,但是d2大于d1,意味着AB之间的紧密度比DE之间的紧密度更加亲密,也就是皮尔逊相关度更高。

接下来我们对每篇博客进行描述,因此建立了一个类:

[python]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. class cluster:  
  2.     def __init__(self, w_list = None, left = None, right = None, node_id = 0, distance = 0.0):  
  3.         self.w_list = w_list   #特征list  
  4.         self.node_id = node_id      #节点id  
  5.         self.left = left            #左节点  
  6.         self.right = right          #右节点  
  7.         self.distance = distance        #离左右节点的距离  

例如对上图中节点1的描述:w_list是A、B博客特征list的平均值,left是A博客,right是B博客,distance是d1的长度。若来描述A,则left和rigth都是None。然后读取我们抓取的每一篇博客,并创建cluster类,组成cluster_list。

[python]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. words_list = []  
  2. cluster_list = list()  
  3. file = codecs.open('frequency.txt''r')            #打开标记特性词的文档  
  4. for line in file:  
  5.     line.strip()  
  6.     words_list.append(line)                         #标记特征词的list  
  7.       
  8. for i in range(100):                                 #打开每一篇博客  
  9.     filename = str(i) + '.txt'  
  10.     try:  
  11.         file = codecs.open(filename, 'r')  
  12.         content = file.read()  
  13.         l = []  
  14.         for word in words_list:  
  15.             l.append(content.count(word))           #每一个标记词在这篇博客中出现的次数  
  16.         cluster_list.append(cluster(w_list = l, node_id = i))       #为这篇博客创建类并append到cluster_list中  
  17.     exceptbreak  


然后我们进行分级聚类:

[python]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. def clustering(cluster_list):      
  2.     k = -1  
  3.     while(len(cluster_list) > 1):  
  4.         dmin = distance(cluster_list[0].w_list, cluster_list[1].w_list)  
  5.         for i in range(len(cluster_list)):                                              #两两比较,找出最小的  
  6.             for j in range(i + 1, len(cluster_list)):  
  7.                 dis = distance(cluster_list[i].w_list, cluster_list[j].w_list)  
  8.                 if dis < dmin or dis == dmin:   
  9.                     dmin = dis  
  10.                     cluster1 = cluster_list[i]  
  11.                     cluster2 = cluster_list[j]  
  12.         l = [(cluster1.w_list[i] + cluster2.w_list[i])/2.0 for i in range(len(cluster1.w_list))]  
  13.           
  14.         newcluster = cluster(w_list = l, left = cluster1, right = cluster2, node_id = k, distance = dmin)       #将紧密度最高的两个cluster进行合并重组  
  15.         cluster_list.append(newcluster)                     #将合并后的cluster添加如cluster_list  
  16.         cluster_list.remove(cluster1)  
  17.         cluster_list.remove(cluster2)                       #移除紧密度最高的两个cluster  
  18.   
  19.         k = k - 1                   #若node_id为负数,则表示这不是叶节点  
  20.     return cluster_list[0]  
其实这里还可以进行优化,《集体智慧编程》中的代码是优化过了的。上述的代码在求distance时重复计算了,每一次计算实际上只需要对合并后的新元素两两求distance即可。


补充:当然了,也可以利用PIL来画树状图。如果大家是win7 64位的系统,推荐大家去http://www.lfd.uci.edu/~gohlke/pythonlibs/进行下载,下载pillow这个包。这个网站上的库都是已经编译好了的,下载后直接安装即可。绘图也不是很麻烦,在绘图时,我突然意识到cluster类中定义left和right的巧妙之处。如果大家有时间也可以画画这个树状图,由于不是学习的主要内容这里就不详细再说了~效果应该大致是这样的:




祝大家学习愉快!


我是一只小蜗牛,看我来慢慢爬上python这座山峰!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值