聚类分析学习笔记(三)

本文是聚类分析的学习笔记第三部分,主要探讨二分K-means算法。这是一种K-means的改进方法,通过逐步分裂簇来寻找最佳的k个簇。目标函数是误差平方和(SSE),算法过程包括基本概念和实现。文章提供了K-means和二分K-means的Python源码实现,使用欧式距离和Person相关系数作为距离度量。
摘要由CSDN通过智能技术生成

聚类分析学习笔记(三)

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

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 np
import 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/den
return 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 centers

def 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, cluster

def 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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值