发现群组(二)分级聚类

来源:互联网 发布:电路板设计软件下载 编辑:程序博客网 时间:2024/06/06 20:15


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

0 0
原创粉丝点击