【spyder】k-means聚类算法的验证

import numpy as np  #导入numpy包,且起名为np
'''numpy是Python中科学计算的基础包,它是一个Python库,提供多维数组对象,
各种派生对象,如掩码数组和矩阵以及用于数组快速操作的各种例程。'''
import matplotlib.pyplot as plt #导入matplotlib库中的pyplot包,并起名为plt
'''(matplotlib.pyplot 是命令行风格的函数集,
  让matplotlib看起来像MATLAB.Each一样工作。
  pyplot函数能够对画布(figure)进行一些改变,例如:创建一个画布(figure), 
  在画布中创建一个绘图区域,在绘图区域中画图,使用文字标签修饰图形。)'''

def L2(vecXi, vecXj):
    
    '''输入:向量vecXi,向量vecXj
    输出:两个向量的欧式距离
    描述:计算两个向量的欧式距离
    
    计算欧氏距离
    para vecXi:点坐标,向量
    para vecXj:点坐标,向量
    return: 两点之间的欧氏距离(距离标量)'''
    
    return np.sqrt(np.sum(np.power(vecXi - vecXj, 2))) 
    #np.sqrt(x):计算数组各元素的平方根,括号里的数必须大于或等于0。
    #numpy中的sum则可以求出矩阵或数组所有元素的和
    #np.power(x, y) 表示x 的y次方,
    #  y=2表示x的平方,y=1/2表示x开方,y =1/3表示x开立方,y= -1表示x的倒数。

def kMeans(S, k, distMeas=L2):
     
    
    '''输入:数据集,k,计算向量间距离的函数名,随机生成k个随机质心的函数名
    输出:包含质心的集合,包含K个随机质心(clusterCents)的集合,簇分配结果矩阵
    描述:kmeans算法实现
    
    K均值聚类
    para S:样本集,多维数组(样本数据集,np数组)
    para k:簇个数
    para distMeas:距离度量函数,默认为欧氏距离计算函数
    return sampleTag:一维数组,存储样本对应的簇标记
    return clusterCents:一维数组,各簇中心
    retrun SSE:误差平方和'''
    
    
    
    #m:获取数据集行数用于后边初始化全0矩阵clusterCents 
    m = np.shape(S)[0]  #样本总数(数据集的行数,即数据的个数)
    sampleTag = np.zeros(m) 
    # 随机产生k个初始簇中心
    n = np.shape(S)[1] # 样本向量的特征数()
    #clusterCents:用于保存结果矩阵
    clusterCents = np.mat([[-3.38822792,-1.75282590],
                [5.65622583,7.53046709],[10.64183154,0.20088133]])
    #clusterCents = np.mat(np.zeros((k,n)))
    #for j in range(n):
    #    minJ = min(S[:,j]) 
    #    rangeJ = float(max(S[:,j]) - minJ)
    #    clusterCents[:,j] = np.mat(minJ + rangeJ * np.random.rand(k,1))
        
    sampleTagChanged = True
    SSE = 0.0
    while sampleTagChanged: # 如果没有点发生分配结果改变,则结束
        sampleTagChanged = False
        SSE = 0.0
        
        # 计算每个样本点到各簇中心的距离
        for i in range(m):
        # 开始 循环 为每一个数据点 分配到距离其最近的类中心
            minD = np.inf# 初始化最小距离为inf(无穷大) 索引为负
            # 开始针对当前数据点 计算其到每个类质心最短的距离 保存最小的距离
            minIndex = -1
            for j in range(k):   #对于每一质心
    # 注意以行为开头 即 行向量 即对每个数据点计算其到每个类中心点的欧氏距离
                d = distMeas(clusterCents[j,:],S[i,:]) #得到数据与质心间的距离
                # 每次进行判断是否比上次距离更小 进行存储更小的距离
                # 直至比较到最后取到最小距离 【不保存所有距离,只保存最小距离】
                if d < minD:  #更新最小值
                    minD = d
                    minIndex = j
            # 如果索引即 该数据点的归属类(簇)发生了改变 就继续进行循环
            if sampleTag[i] != minIndex: 
                sampleTagChanged = True
     # 此时再进行更新该数据点的(索引)归属类,和距离该归属类质(或中)心最小距离。
            sampleTag[i] = minIndex
            SSE += minD**2
        print(clusterCents)
        plt.scatter(clusterCents[:,0].tolist(),clusterCents[:,1].tolist(),
                    c='blue',marker='*',linewidths=7)
        #plt.scatter()绘制散点图  【c:颜色(默认是蓝色'b'); 
        #marker:标记(点的形状)(默认的是'o')
        #linewidths:也就是标记点的长度。】
        plt.scatter(S[:,0],S[:,1],c=sampleTag,
                    linewidths=np.power(sampleTag+0.5, 2))
        plt.show()
        print(SSE)
        
        # 重新计算簇中心
        for i in range(k): #对于每一个簇
            # 下面用于找到 当前类质心 下的所有数据点
            ClustI = S[np.nonzero(sampleTag[:]==i)[0]] 
            #通过数组过滤得到簇中所有数据
            clusterCents[i,:] = np.mean(ClustI, axis=0) 
            #将质心更新为簇中所有数据的均值 
            #axis=0表示沿矩阵的列方向计算均值
    return clusterCents, sampleTag, SSE

if __name__=='__main__':
    samples = np.loadtxt("kmeansSamples.txt") #调用numpy的包
    clusterCents, sampleTag, SSE = kMeans(samples, 3) #调用kMeans函数
    #plt.scatter(clusterCents[:,0].tolist(),
    #   clusterCents[:,1].tolist(),c='r',marker='^')
    #plt.scatter(samples[:,0],samples[:,1],c=sampleTag,
    #   linewidths=np.power(sampleTag+0.5, 2))
    plt.show()
    print(clusterCents)
print(SSE)

运行结果:
【spyder】k-means聚类算法的验证
【spyder】k-means聚类算法的验证
【spyder】k-means聚类算法的验证
【spyder】k-means聚类算法的验证
相关链接

上一篇:Spark学习笔记——龟速更新。。


下一篇:Spyder和Python有什么关系?功能介绍!