k-means聚类算法原理及python3实现

 

本文完成程序及测试数据集详细见:https://github.com/HanXia001/k-means-python3-

本文主要内容:

                1.k-means解决的问题;

                2.k-means原理介绍;

                3.k-means的简单实现。

1.k-means解决的问题

         k-means算法属于无监督学习的一种聚类算法,其目的为:在不知数据所属类别及类别数量的前提下,依据数据自身所暗含的特点对数据进行聚类。对于聚类过程中类别数量k的选取,需要一定的先验知识,也可根据“类内间距小,类间间距大“(一种聚类算法的理想情况)为目标进行实现。

2.k-means原理介绍

        k-means算法以数据间的距离作为数据对象相似性度量的标准,因此选择计算数据间距离的计算方式对最后的聚类效果有显著的影响,常用计算距离的方式有:余弦距离、欧式距离、曼哈顿距离等。本文以欧式距离为例(会一种,其余也就会了)。

欧式距离公式:

                                                                  

例子:若数据为其计算欧式距离如下(可理解为D表示维度,i,j表示行数):

                                                                

         通过公式(1)可计算出每对数据对象间的距离,根据距离的远近进行聚类成指定的类别数K。对每一类中的数据初步选取类心,取的方式有多种如:

                             1.该类所有数据的均值;

                             2.随机取k个数据作为类心;

                             3.选取距离最远的k个点作为类心等。

以上方法均需要对初步的类心进行迭代,当类心变化缓慢时便可认为收敛,此时该点便为最终的类型。本文以方法1为例:

                                                                  

表示第k类,表示第k类中数据对象的个数。类心迭代过程如下:

                                                              

通常迭代终止的条件有两种:1)达到指定的迭代次数T;2)类心不再发生明显的变化,即收敛。

3.k-means的简单实现

原理讲过,此处直接上代码(python3实现):

import numpy as np
import matplotlib.pyplot as plt

# 加载数据
def loadDataSet(fileName):
    data = np.loadtxt(fileName,delimiter='\t')
    return data

# 欧氏距离计算
def distEclud(x,y):
    return np.sqrt(np.sum((x-y)**2))  # 计算欧氏距离

# 为给定数据集构建一个包含K个随机质心的集合
def randCent(dataSet,k):
    m,n = dataSet.shape
    centroids = np.zeros((k,n))
    for i in range(k):
        index = int(np.random.uniform(0,m)) #
        centroids[i,:] = dataSet[index,:]
    return centroids

# k均值聚类
def KMeans(dataSet,k):

    m = np.shape(dataSet)[0]  #行的数目
    # 第一列存样本属于哪一簇
    # 第二列存样本的到簇的中心点的误差
    clusterAssment = np.mat(np.zeros((m,2)))
    clusterChange = True

    # 第1步 初始化centroids
    centroids = randCent(dataSet,k)
    while clusterChange:
        clusterChange = False

        # 遍历所有的样本(行数)
        for i in range(m):
            minDist = 100000.0
            minIndex = -1

            # 遍历所有的质心
            #第2步 找出最近的质心
            for j in range(k):
                # 计算该样本到质心的欧式距离
                distance = distEclud(centroids[j,:],dataSet[i,:])
                if distance < minDist:
                    minDist = distance
                    minIndex = j
            # 第 3 步:更新每一行样本所属的簇
            if clusterAssment[i,0] != minIndex:
                clusterChange = True
                clusterAssment[i,:] = minIndex,minDist**2
        #第 4 步:更新质心
        for j in range(k):
            pointsInCluster = dataSet[np.nonzero(clusterAssment[:,0].A == j)[0]]  # 获取簇类所有的点
            centroids[j,:] = np.mean(pointsInCluster,axis=0)   # 对矩阵的行求均值

    print("Congratulations,cluster complete!")
    return centroids,clusterAssment

def showCluster(dataSet,k,centroids,clusterAssment):
    m,n = dataSet.shape
    if n != 2:
        print("数据不是二维的")
        return 1

    mark = ['or', 'ob', 'og', 'ok', '^r', '+r', 'sr', 'dr', '<r', 'pr']
    if k > len(mark):
        print("k值太大了")
        return 1

    # 绘制所有的样本
    for i in range(m):
        markIndex = int(clusterAssment[i,0])
        plt.plot(dataSet[i,0],dataSet[i,1],mark[markIndex])

    mark = ['Dr', 'Db', 'Dg', 'Dk', '^b', '+b', 'sb', 'db', '<b', 'pb']
    # 绘制质心
    for i in range(k):
        plt.plot(centroids[i,0],centroids[i,1],mark[i])

    plt.show()
dataSet = loadDataSet("test.txt")
k = 4
centroids,clusterAssment = KMeans(dataSet,k)

showCluster(dataSet,k,centroids,clusterAssment)

效果如图:

                                                                           

所用数据有些少,因此效果不明显。

猜你喜欢

转载自blog.csdn.net/hanxia159357/article/details/81530361