聚类分析学习笔记(三)

来源:互联网 发布:linux man命令怎么用 编辑:程序博客网 时间:2024/05/01 22:45

聚类分析学习笔记(三)

此笔记参考了数据挖掘导论、周志华的机器学习以及机器学习实战三本书

4.二分K-means算法

4.1 基本概念

二分K-means算法是对K-means算法的一种改进,它基于一种简单的思想:为了得到k个簇,将所有点的集合分裂成两个簇,从这些簇中选取一个继续分裂,如此下去,直到产生k个簇。

度量聚类质量的目标函数:误差的平方和SSE,即计算每个样本到所在簇的质心的距离的平方和,SSE越小越好。

SSE=i=1kxCidist(μi,x)2

4.2 二分K-means算法过程

初始化簇表,将所有数据点看成一个簇repeat    从簇表中取出每一个簇    for i=1 to 此时簇的个数 do        使用K-means算法,二分选定的簇    end for    从二分试验中选取具有最小SSE的两个簇    删除原簇,将由原簇划分的两个簇添加进簇表中until 簇表中包含k个簇
4.3 K-means算法和二分K-means算法源码

下面是K-means算法和二分K-means算法的python源码,参考了机器学习实战一书,计算距离采用的是欧式距离,当然也可以用其他参数来度量(例如明可夫斯基距离,曼哈顿距离以及person相关系数等等),除了实现欧式距离,下面的代码还实现了person相关系数的求取方法。

# -*- coding:utf-8 -*-import numpy as npimport math# 欧式距离def oushi_distance(vec1, vec2):    distance = math.sqrt(sum([math.pow(vec1[0, i]-vec2[0, i], 2) for i in range(0, np.shape(vec2)[1])]))    return distance# person相关def person_distace(vec1, vec2):    n = len(vec1)    sum1_sq = sum([math.pow(vec1[0, i], 2) for i in range(0, np.shape(vec2)[1])])    sum2_sq = sum([math.pow(vec2[0, i], 2) for i in range(0, np.shape(vec2)[1])])    sum1 = np.sum(vec1)    sum2 = np.sum(vec2)    psum = sum([vec1[0, i]*vec2[0, i] for i in range(0, np.shape(vec2)[1])])    num = psum-(sum1*sum2/n)    den = math.sqrt((sum1_sq-math.pow(sum1, 2)/n)*(sum2_sq-math.pow(sum2, 2)/n))    distance = num/denreturn distance# 初始化质心def randCent(dataSet, k):    n = np.shape(dataSet)[1]  # 特征数    centers = np.mat(np.zeros((k, n)))  # k*n(k个中心向量)    for j in range(n):        min_j = min(dataSet[:, j])        range_j = float(max(dataSet[:, j]) - min_j)        centers[:,j] = np.mat(min_j + range_j * np.random.rand(k, 1))    return centersdef kmean(dataSet, k):    m = np.shape(dataSet)[0]  # 样本数    cluster= np.mat(np.zeros((m, 2)))  # 存放样本所属簇以及最短距离    centers = randCent(dataSet, k)  # k*n(k个中心向量)    clusterChange = True # 判断聚类停止的条件    while clusterChange:        clusterChange = False        minDist=np.inf        minIndex = -1        for i in range(m):            for j in range(k):                dist_ji = oushi_distance(centers[j, :], dataSet[i, :])                if dist_ji<minDist:                    minDist=dist_ji**2                    minIndex=j            if cluster[i,0]!=minIndex:                clusterChange = True            cluster[i, 0]=minIndex            cluster[i, 1]=minDist            # 更新中心点,centers(k*n)            for center in range(k):                Cluster_k = dataSet[np.nonzero(cluster[:, 0].A == center)[0]]                centers[center, :]=np.mean(Cluster_k, axis=0) # 按列相加        return centers, clusterdef bikeanms(dataSet, k):    m=np.shape(dataSet)[0]    cluster = np.mat(np.zeros((m, 2)))  # 存放样本属于哪个簇以及最短距离    center0=np.mean(dataSet, axis=0).tolist()[0] # 求每列的平均    centerlist=[center0] # 将第一个中心放入centerlist中    for j in range(m):        cluster[j, 1]=(oushi_distance(np.mat(center0), dataSet[j, :]))**2    while(len(centerlist)<k):        minSSE=np.inf        for i in range(len(centerlist)):            CurrCluster = dataSet[np.nonzero(cluster[:, 0].A == i)[0], :] # 第i个簇里所有样本            splitCenter, splitCluster=kmean(CurrCluster, 2)            sseSplit = sum(splitCluster[:, 1])            sseNotSplit = sum(cluster[np.nonzero(cluster[:, 0].A != i)[0], 1])            if (sseSplit + sseNotSplit) < minSSE:                bestsplitCenter=i                bestNewCenter = splitCenter                bestNewCluster = splitCluster.copy()                minSSE = sseSplit + sseNotSplit        bestNewCluster[np.nonzero(bestNewCluster[:, 0].A == 1)[0], 0] = len(centerlist)        bestNewCluster[np.nonzero(bestNewCluster[:, 0].A == 0)[0], 0] = bestsplitCenter        centerlist[bestsplitCenter] = bestNewCenter[0, :].tolist()[0]        centerlist.append(bestNewCenter[1, :].tolist()[0])        cluster[np.nonzero(cluster[:, 0].A == bestsplitCenter)[0], :] = bestNewCluster    return np.mat(centerlist), cluster
0 0