K-均值聚类算法 机器学习

前言:

    K-均值聚类是无监督学习,聚类算法中的一种,也比较简单。主要用于视觉图像分类,视频分析,基因分析,

自然语言处理文本分析,图像分割等算法(二值化)

     主要应用场景,图片聚类,行程安排(一群人安排班车,选择合适的地点,总距离最小)

目录

  1.      算法流程
  2.     后处理提高聚类性能
  3.      二分K-均值算法
  4.       例子

一    算法流程

    

     也叫基于质心的算法。它的样本划分为k个类,参数由人工设定。

     假设有m个n维样本,

    初始化k个中心向量 u_1,u_2,....u_k

     循环(终止条件 样本中心点变化小于预设值)

                1.1 根据当前的类中心,确定每个样本所属于的类

                分配样本: 

                       循环:

                                  对每个样本x_i

                                       d_{ij}=||x_i-u||

                                   将样本分配到距离最近的那个点

                         结束循环

                         更新样本中心:

                    1.2  循环,对每个类

                     根据上面的分配方案更新每个类的中心

                                                u_i =\sum_{j=1,y_j=i}^{m} \frac{x_j}{N_i}

                                               y_j 为样本j的类别

                                               N_i 为第i类的样本数

                 

# -*- coding: utf-8 -*-
"""
Created on Thu Dec 12 16:37:40 2019

@author: chengxf2
"""

from numpy import *
import os
import matplotlib.pyplot as plt

"""
加载数据集
Args
    None

return 
    dataMat: 数据集
"""
def LoadData():
    path = os.path.abspath("testSet.txt")
    
    f = open(path)
    dataMat =[]
    
    for line in f.readlines():
        
        curLine = line.strip().split("\t")
        floatLine = list(map(float, curLine))
        dataMat.append(floatLine)
        
    return np.mat(dataMat)


"""
初始化聚类中心
Args:
    dataMat: 数据集
    k: 分类种类
return
   U: 聚类中心点
"""
def RandCent(dataMat, k):
    
    m,n = np.shape(dataMat)
    
    
    U = np.mat(np.zeros((k,n)))
    
    for j in range(n):
        minJ = min(dataMat[:,j])
        maxJ = max(dataMat[:,j])
        rangeJ = float(maxJ-minJ)
        
        U[:,j]=minJ+rangeJ*np.random.rand(k,1)
        
    print("\n U ",U)
    return U
    
"""
欧式距离计算
Args
   vecA
   vecB
"""
def Dist(vecA, vecB):
    
    vecC = vecA-vecB
    dist = vecC*vecC.T
    
    return float(dist)


"""
获得欧式距离
Args
   dataMat: 数据集
   k:  分类种类
   distMeas: 欧式距离计算
   createCent: 随机选择中心
"""
def kMean(dataMat, k, distMeas = Dist, createCent = RandCent):
    
    m,n = np.shape(dataMat)
    
    search = True
    U = RandCent(dataMat, k) ##聚类中心点
    cluster = np.mat(np.zeros((m,2)))##第一个是当前样本点归类,第二个欧式聚类
    
    iter = 0
    
    while search:
        search = False
        iter +=1
        for i in range(m):
            minDist = np.inf
            minIndex = -1
            vecA = dataMat[i,]
            
            for j in range(k):
                vecB = U[j,]
                distIJ = distMeas(vecA, vecB)
                
                if distIJ< minDist:
                    minDist = distIJ
                    minIndex  = j
           
            if cluster[i,0]!= minIndex:
                search = True
            cluster[i,:]= [minIndex,minDist**2]
           
        for j in range(k):
            ClusterJ = dataMat[np.nonzero(cluster[:,0].A == j)[0]]
          
            U[j,:]= np.mean(ClusterJ,axis =0)
        print("\n iter::::::::\n ",iter)
    return U, cluster
            
    
     
def Test():
    dataMat = LoadData()
    k =4
    U, cluster =kMean(dataMat, k)
    marker =["^","o","<","s","x","8"]
    color = ["b","c","g","r","y","k"]
    m,n = np.shape(dataMat)
    print("====================")
    
    for i in range(m):
        t = int(cluster[i,0])
       # print("k ",k)
        co = color[t]
        mk = marker[t]
        x = dataMat[i,0]
        y = dataMat[i,1]
        
        plt.scatter(x,y,c=co, marker = mk,s=10)
    
    
    for j in range(k):
        
        x = U[j,0]
        y = U[j,1]
        co = color[j]
        mk = marker[j]
        print("x: ",x,"y: ",y)
        plt.scatter(x,y,c=co, marker = mk,s=200)
    plt.show()
    
    
    
    #print("\n dist ",U,"\n cluster : \n ",cluster)
    
    
Test()        

     

   


二 后处理提高性能

      

   K均值算法收敛但聚类效果差的原因:

              由于质心的随机初始化,K均值算法可能会收敛到局部最小值。 
一种度量聚类效果的指标是SSE(误差平方和),但必须在保持簇数目不变的情况下提高簇的质量。

  聚类效果评价指标SSE

  SSE(Sum of Squared Error,误差平方和)

       SE值越小表示数据点越接近于它们的质心,聚类效果也越好。因为对误差取了平方,因此更加重视那些远离中心的点。所以,应该想办法使得SSE尽可能的小。 

 

  改进的方法是对生成的簇进行后处理,将最大SSE值的簇划分成两个(K=2的K-均值算法),然后再进行相邻的簇合并。具体方法有两种:

                    1、合并最近的两个质心(合并使得SSE增幅最小的两个质心)

                    2、遍历簇 合并两个然后计算SSE的值,找到使得SSE最小的情况。 

 

    具体可以参照下面的二分K-均值算法

 

   


三  二分-均值算法

       所有的点看作一个簇

       当簇小于数目k时候

                   对每个簇:

                               计算总误差

                               在给定的的簇上面进行K-均值聚类(K=2)

                               计算将该簇一份为2后的总误差

                    选择使得误差最小的簇 进行划分操作

"""
二分K 均值算法
"""
def MeanK(dataMat, k):
    
    m,n = np.shape(dataMat)
    
    cluster =np.mat(np.zeros((m,2)))  ##第一个当前的类,第二个当前距离
 
    u= np.mean(dataMat, axis=0).tolist()[0] ##开始只有一个中心点
    print("\n ************** u0 ********\n ",u)  
    u_List =[u]
    vecB = np.mat(u)
    
    for j in range(m):
        vecA = dataMat[j,]
        
        dist = Dist(vecA, vecB)
        cluster[j,1]= dist
        #print("\n i ",i,"\t dist: \t ",dist)
    iter = 0
    while (len(u_List)<k):  ##小于聚类总数
          minSSE = np.inf
          n = len(u_List)
          iter =iter+1
          #print("\n **********iter: **********",iter)
          for i in range(n):
              print("\n i: ",i)
              curCluster = dataMat[np.nonzero(cluster[:,0].A==i)[0],:]
              u, splitCluster = kMean(curCluster, 2)
              SSE1 = np.sum(splitCluster[:,1])
              SSE2Index = np.nonzero(cluster[:,0].A!=i)[0]
              #print("\n SSE2Index: ",SSE2Index)
              if len(SSE2Index)==0:
                  SSE2 = 0.0
              else:
                  SSE2 = np.sum(cluster[SSE2Index,1])
              
              if (SSE1+SSE2)<minSSE:
                  bestIndex = i
                  bestU = u
                  bestCluster = splitCluster.copy()
                  minSSE = SSE1+SSE2
            
          bestCluster[np.nonzero(bestCluster[:,0].A == 1)[0],0] = int(len(u_List))  ##新的
          bestCluster[np.nonzero(bestCluster[:,0].A == 0)[0],0] = int(bestIndex)  ##old
        
          u_List[bestIndex]=bestU[0,:]
          u_List.append(bestU[1,:])
          cluster[np.nonzero(cluster[:,0].A == bestIndex)[0],:] = bestCluster
        
    print("\n ********uList*****\n",u_List)
    return u_List,cluster
        
        

参考文档

  《机器学习与应用》

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值