发现群组(二)分级聚类


python基础

字符串处理方法:

string.lstrip() 截掉string 左边的空格

string.rstrip() 删除string 字符串末尾的空格

string.split(str="", num=string.count(str)) 以str 为分隔符切片string,如果num有指定值,则仅分隔num 个子字符串

 序列操作符
(1)切片( [ ] 和 [ : ] )

对任何范围[start:end],我们可以访问到包括start 在内到end(不包括end)的所有字符

>>> aString = 'abcd'
>>> aString[1:3]
'bc'
>>> aString[2:4]
'cd'

反向索引

>>> aString[-1]
'd'
>>> aString[-3:-1]
'bc'
如果开始索引或者结束索引没有被指定,则分别以字符串的第一个和最后一个索引值为默认值。

>>> aString[2:]
'cd'
>>> aString[1:]
'bcd'
>>> aString[:-1]
'abc'
(2)总述
序列操作符                              作用
seq[ind]                       获得下标为ind 的元素
seq[ind1:ind2]           获得下标从ind1 到ind2 间的元素集合
seq * expr                  序列重复expr 次
seq1 + seq2            连接序列seq1 和seq2
obj in seq                 判断obj 元素是否包含在seq 中

obj not in seq          判断obj 元素是否不包含在seq 中

(3) 序列的操作方法

len(seq)                                   返回seq 的长度

reversed(seq)                        接受一个序列作为参数,返回一个以逆序访问的迭代器(PEP 322)

sum(seq, init=0)                    返回seq 和可选参数init 的总和, 其效果等同于reduce(operator.add,seq,init)

特别注意上述接口的参数类型都为序列 (列表,数组、字典等),和我们平时用的C语言等函数参数的概念是有所差异的。

class 类

构造实例的方法:

在创建类时,可以通过重构__new__方法来构造对象的一个实例等,此方法和C++等语言中的new函数构造对象的方法是一致的。

通过重构__init__方法,实现初始化。

__new__(cls, *args, **kwargs)  创建对象调用,返回当前对象的一个实例;注意:这里的第一个参数是cls即class本身
__init__(self, *args, **kwargs) 创建完对象调用,对当前对象的实例的一些初始化,无返回值,即在调用__new__之后,根据返回的实例初始化;注意,这里的第一个参数是self即对象本身【注意和new的区别】

分级聚类

算法

     将每一行的数据视为一个对象,构建描述此对象的类(bicluster)。而后使用皮尔逊相关度(当然也可以用其他相关度的算法)算法,计算每两个对象之间的亲密度(计算量大),先找出最亲密的两个节点,作为叶子节点,而后以此两个节点构造他们的父节点(父节点的值为两个子节点中各个数据的平均值),以此循环,直到所有的行数据对象被处理完毕,最终形成一个二叉树的结构。

     实际上即是由一个链表(行数据读入后存在在一个rows列表中),构造一个二叉树的过程。构造的控制过程由具体算法控制。

代码实现    

最终的代码如下:

   

# coding=utf-8
from math import sqrt
import codecs
#解析blogdata数据
def readfile(filename):
    file=codecs.open('blogdata.txt','r','utf-8')
    lines=[line for line in file.readlines()]
    #将文件的第一行(单词)拆分成单词列表,存放到colnames中
    colnames=lines[0].strip().split('\t')[1:]
    rownames=[]
    data=[]
    for line in lines[1:]:   #对于除第一行之外,剩余的行进行处理
        p=line.strip().split('\t')
        rownames.append(p[0])  #每行对应的列表的第一个元素为博客title,单独存放,作为行名称
        #本行中剩余的为单词 出现次数的统计
        data.append([float(x) for x in p[1:]])
       # print data
    file.close()
    return rownames,colnames,data  #所有单词出现的次数都存在data中,这个怎么知道是哪个单词在哪篇里面出现的次数了??

#皮尔逊相关度的实现
def pearson(v1,v2):
    #简单求和
    sum1= sum(v1)  #参数v1和v2是一个数据列表
    sum2=sum(v2)
    #求平方和
    sum1Sq=sum(pow(v,2) for v in v1)
    sum2Sq=sum(pow(v,2) for v in v2)
    #求乘积之和
    pSum =sum([v1[i]*v2[i] for i in range(len(v1))])
    
    #计算 r(Pearson score)
    print "sum1 :%f" % sum1Sq
    print "sum2 :%f" % sum2Sq
    print "pow1 :%f" % pow(sum1,2)
    print "pow2 :%f" % pow(sum2,2)
    
    num = pSum-(sum1*sum2)/len(v1)
    den =sqrt((sum1Sq-pow(sum1,2)/len(v1))*(sum2Sq-pow(sum2,2)/len(v2)))
    
    if den == 0: return 0
    return 1.0-num/den     #相似值越大,表示距离越小

#聚类节点,left riight相当于二叉树定义中的两个左右孩子指针
class bicluster:
    def __init__(self,vec,left=None,right=None,distance=0.0,id=None):
        self.left=left
        self.right=right
        self.vec=vec
        self.id=id
        self.distance=distance

#之前构造的数据文件,经过readfile转化后,每行代表一篇博客,每行看做一个聚类前的原始节点,然后
#开始计算每个节点之间的距离,并根据距离构造聚类关系的二叉树
def hcluster(rows,distance=pearson): #这里注意,函数的第二个参数为函数(理解为c语言中的函数指针)
    distances={}  #定义一个字典,记录各个节点亲密度 。键为两个节点的ID,值为两个节点的距离
    currentclustid=-1   #
    
    #针对每一行rows[i],将其创建为一个bicuster的一个实例,其ID为行号。vec是个列表类型,代表一行的数据. clust为各行数据实例化后的集合
    clust=[bicluster(rows[i],id=i) for i in range(len(rows))]
    
    while len(clust)>1:   #逐步把clust这个列表 集合构造成 聚类的二叉树形式,最后只剩一个根节点
        lowestpair=(0,1)   # 初始值,现在还不清楚具体哪两个节点(即行数据)关系近
        closest=distance(clust[0].vec,clust[1].vec)  #这里使用皮尔逊相似度算法计算两组数据之间的关系亲密度
        
        for i in range(len(clust)):  # 针对每一行的数据
            for j in range(i+1,len(clust)): #针对i后面的N行数据
                if (clust[i].id,clust[j].id) not in distances:
                    distances[(clust[i].id,clust[j].id)]=distance(clust[i].vec,clust[j].vec)   #计算所有 节点(每行博客数据)的亲密度,并保存在字典distances中
                d=distances[(clust[i].id,clust[j].id)]
                if d<closest:     #找距离最小的节点,开始聚类
                    closest=d
                    lowestpair=(i,j)
        #计算两个距离最小节点的平均值,作为一个新的虚拟节点。
        mergevec=[(clust[lowestpair[0]].vec[i]+clust[lowestpair[1]].vec[i])/2.0 for i in range (len(clust[0].vec))]
        
        #生成一个新的对象实例,作为聚类树的枝干节点
        newcluster=bicluster(mergevec,left=clust[lowestpair[0]],right=clust[lowestpair[1]],distance=closest,id=currentclustid)
        
        currentclustid -=1

        del clust[lowestpair[1]]
        del clust[lowestpair[0]]        
        clust.append(newcluster) # 将新节点追加到列表中
    return clust[0]  #返回最后的根节点
    
#打印聚类后的数据
def printclust(clust,labels=None,n=0):
    for i in range(n): print ' ',
    if clust.id<0:
        print '---'
    else:
        if labels == None: print clust.id
        else: print labels[clust.id]
    if clust.left != None: printclust(clust.left,labels=labels,n=n+1)
    if clust.right != None: printclust(clust.right,labels=labels,n=n+1)
    
if __name__ =='__main__':
    blogname,words,data=readfile("blogdata.txt")
   
    clust=hcluster(data)
    printclust(clust,blogname)
    

其中上述代码,在readfile接口中处理后,得到的data数据为:总共五个元素,每个元素为一行数据

[[4.0, 0.0, 6.0, 2.0, 0.0, 0.0, 2.0, 10.0, 2.0, 0.0, 0.0, 12.0, 0.0, 0.0, 15.0,
3.0, 0.0, 0.0, 2.0, 0.0, 16.0, 6.0, 0.0, 0.0, 0.0, 2.0, 0.0, 8.0, 0.0, 0.0], [0.
0, 3.0, 2.0, 0.0, 20.0, 0.0, 0.0, 1.0, 0.0, 0.0, 2.0, 0.0, 2.0, 4.0, 0.0, 0.0, 5
.0, 1.0, 0.0, 0.0, 0.0, 0.0, 3.0, 0.0, 4.0, 2.0, 3.0, 1.0, 3.0, 0.0], [2.0, 0.0,
 0.0, 4.0, 144.0, 11.0, 4.0, 0.0, 11.0, 6.0, 2.0, 6.0, 2.0, 0.0, 3.0, 0.0, 0.0,
31.0, 9.0, 2.0, 13.0, 17.0, 1.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0, 8.0], [0.0, 0.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 2.0, 0.0, 0.0
, 0.0, 4.0, 0.0, 4.0, 0.0, 3.0, 1.0, 0.0, 0.0, 2.0, 0.0, 2.0, 4.0, 4.0, 0.0, 1.0
, 0.0, 0.0, 3.0, 4.0, 8.0, 0.0, 3.0, 2.0, 3.0, 2.0]]

程序运行结果

---
  摇摆少年梦的技术博客
  ---
    郭霖的专栏
    ---
      yxyhack's blog
      ---
        anzhsoft的技术专栏
        雷霄骅(leixiaohua1020)的专栏

看起来最后两个相似度很高的,实际并不高。这就是因为在前一篇中所描述的,数据源构造出现的问题。毕竟咱们是中文的帖子。

总结

 算法耗时。后面还有其他的聚类算法,诸如K-means等。聚类是无监督学习,主要是在数据中寻找某种结构(关联?)、将数据分成不同的群组。主要需要关注:相关度算法、聚类算法。后续会采用其他数据源,并采用不同的相关度算法计算数据之间的亲密度,最终用分级聚类展示,例如可以采取某些人关注的某些书,进而建立人和书的二维关系,而后聚类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

proware

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值