统计学习方法 第十四章 聚类方法

聚类方法属于挖掘数据纵向结构的方法(假设为m*n矩阵,m为数据维度或者属性,n为数据个数),依据其特征的相似度或者距离进行归并到若干个“类”或者“簇”的过程。聚类属于无监督学习。常用的两种聚类算法:层次聚类(分聚合以及分裂两种算法)、k均值聚类算法。
聚类的相似度或距离,有4种方法:闵可夫斯基距离,马哈拉诺比斯距离,相关系数,夹角余弦。通过定义距离之后就可以定义族或者簇,并定义类与类之间的距离。
层次聚类假设类别之间存在层次结构,将样本聚到层次化的类中,这里不细讨论,主要描述k均值聚类算法。
k均值聚类算法是一个迭代的过程,每次迭代包括两个步骤,首先选择k个类中心,将样本指派到最近的中心的类中,得到一个聚类结果;然后更新每个类的样本的均值,作为类的新的中心;重复以上步骤,直到收敛为止。
伪代码如下:
创建k个点作为起始质心(通常是随机选择)
当任意一个点的簇分配结果发生改变时
对数据集中的每个数据点
对每个质心
计算质心与数据点之间的距离
将数据点分配到距其最近的簇
对每一个簇,计算簇汇总所有点的均值并将其作为质心
python代码实现如下:
(注意代码里的数据行列意义与开始定义有所不同,每行代表各个数据,每列代表数据的维度或属性,下同)

import numpy as np
#距离计算
def dist_eclud(vec_a,vec_b):
    return np.sqrt(np.sum(np.power(vec_a - vec_b,2)))
    
#构造质心
def rand_cent(data_set,k):
    n = np.shape(data_set)[1]
    centroids = np.mat(np.zeros((k,n)))
    for j in range(n):
        min_j = min(data_set[:,j])
        range_j = float(max(data_set[:,j]) - min_j)
        centroids[:,j] = min_j + range_j * np.random.rand(k,1)
    return centroids

#k均值算法
def k_means(data_set,k,dist_meas = dist_eclud,create_cent = rand_cent):
    m = np.shape(data_set)[0]
    cluster_assment = np.mat(np.zeros((m,2)))
    centroids = create_cent(data_set,k)
    cluster_changed = True
    while cluster_changed:
        cluster_changed = False
        for i in range(m):
            min_dist = np.inf
            min_index = -1
            #寻找最近的质心
            for j in range(k):
                dist_ji = dist_meas(centroids[j,:],data_set[i,:])
                if dist_ji < min_dist:
                    min_dist = dist_ji
                    min_index = j
            if cluster_assment[i,0] != min_index:
                cluster_changed = True
            cluster_assment[i,:] = min_index,min_dist**2
        #更新质心的位置
        for cent in range(k):
            pts_in_clust = data_set[np.nonzero(cluster_assment[:,0].A == cent)[0]]
            centroids[cent,:] = np.mean(pts_in_clust,axis = 0)
    return centroids,cluster_assment

由于k均值聚类算法是一个收敛到局部最小值而非全局最小值的算法,因此作出改良,在保持簇数目不变的情况下提高簇的质量,通过对簇的划分,计算损失函数sse是否降到最低,划分过程不断重复,直到得道指定的簇数目为止。二分k均值伪代码如下:
将所有点看成一个簇
当簇数目小于k时
对每一个簇
计算总误差
在给定的簇上面进行k均值分类(k=2)
计算将该簇一分为二之后的总误差
选择使得误差最小的那个簇进行划分操作
python代码实现如下:

#二分k均值
def bi_kmeans(data_set,k,dist_meas = dist_eclud):
    m = np.shape(data_set)[0]
    cluster_assment = np.mat(np.zeros((m,2)))
    #创建一个初始簇
    centroid0 = np.mean(data_set,axis = 0).tolist()[0]
    cent_list = [centroid0]
    for j in range(m):
        cluster_assment[j,1] = dist_meas(np.mat(centroid0),data_set[j,:]) **2
    while len(cent_list) < k:
        lowest_sse = np.inf
        for i in range(len(cent_list)):
        #尝试划分每一个簇
            pts_in_curr_cluster = data_set[np.nonzero(cluster_assment[:,0].A == i)[0],:]
            centroid_mat,split_clust_ass = k_means(pts_in_curr_cluster,2,dist_meas)
            sse_split = np.sum(split_clust_ass[:,1])
            sse_not_split = np.sum(cluster_assment[np.nonzero(cluster_assment[:,0].A != i)[0],1])
            print("sse_split,and not split :",sse_split,sse_not_split)
            if sse_split + sse_not_split < lowest_sse:
                best_cent_to_split = i
                best_new_cents = centroid_mat
                best_clust_ass = split_clust_ass.copy()
                lowest_sse = sse_split + sse_not_split
        #更新簇的分配结果
        best_clust_ass[np.nonzero(best_clust_ass[:,0].A == 1)[0],0] = len(cent_list)
        best_clust_ass[np.nonzero(best_clust_ass[:,0].A == 0)[0],0] = best_cent_to_split
        print("the best cent to split is :",best_cent_to_split)
        print("the len of best clust ass is :",len(best_clust_ass))
        cent_list[best_cent_to_split] = best_new_cents[0,:]
        cent_list.append(best_new_cents[1,:])
        cluster_assment[np.nonzero(cluster_assment[:,0].A == best_cent_to_split)[0],:] = best_clust_ass
    return cent_list,cluster_assment
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值