利用K-均值聚类算法对未标注数据进行分组

利用K-均值聚类算法对未标注数据进行分组

实验数据:

testSet.txt,每行包含两个数值型数据

实验要求:

利用K-均值聚类算法对数据进行分组,由于是无标注数据,实验结果为误差平方和,这里的误差是一个点到簇中心的距离。

实验步骤:

1.处理数据:将数据转化为矩阵形式,函数为loadDataSet(fileName),注释:fileName为文件名称,输出为数据集的矩阵形式;

2.距离计算:计算点到簇中心的距离,使用欧式距离即可,函数为distEclud(vecA,vecB),vecA和vecB分别是数据点和簇中心的坐标

3.初始化簇中心:随机质心必须要在整个数据集的边界之内,可以用列的最小值+random.rand(k,1)*该列的最大值和最小值之差来得到,函数为randCent(dataSet,k),dataSet为数据矩阵,k表示有k个质心,输出为初始质心;

4.K-均值聚类算法:伪代码如下:

  创建k个点作为起始质心

  当任意一个点的簇分配结果发生改变时

       对数据集中的每个数据点

            对每个质心计算质心与数据点之间的距离

            将数据点分配到距其最近的簇,并保存该点到簇中心的距离

       对每一个簇,计算簇中所有点的均值并将均值作为质心

函数为kMeans(dataSet,k),dataSet为数据矩阵,k表示有k个质心,输出为质心、每个点所属的类别和误差,这里的误差是当前点到簇质心的距离;

5.测试算法:使用量化的误差指标误差平方和来评价算法的结果,函数为metric(clusterAssment),clusterAssment包含两列,一列记录索引值,一列记录误差,返回误差平方和。

import matplotlib.pyplot as plt
from numpy import *


# 加载数据
def loadDataSet(fileName):  # 解析文件,按tab分割字段,得到一个浮点数字类型的矩阵
    dataMat = []  # 文件的最后一个字段是类别标签
    fr = open(fileName)
    for line in fr.readlines():
        curLine = line.strip().split('\t')
        curLine = [float(i) for i in curLine]  # 将每个元素转成float类型
        dataMat.append(curLine)
    return dataMat


# 计算欧几里得距离
def distEclud(vecA, vecB):
    return sum(power(vecA - vecB, 2))  # 求两个向量之间的距离


def randCent(dataSet, k):
    n = shape(dataSet)[1]
    centroids = mat(zeros((k, n)))  # 每个质心有n个坐标值,总共要k个质心
    for j in range(n):
        minJ = min(dataSet[:, j])
        maxJ = max(dataSet[:, j])
        rangeJ = float(maxJ - minJ)
        centroids[:, j] = minJ + rangeJ * random.rand(k, 1)
    return centroids


# k-means 聚类算法
def kMeans(dataSet, k, distMeans=distEclud, createCent=randCent):
    m = shape(dataSet)[0]
    clusterAssment = mat(zeros((m, 2)))  # 用于存放该样本属于哪类及质心距离
    #  clusterAssment第一列存放该数据所属的中心点,第二列是该数据到中心点的距离
    centroids = createCent(dataSet, k)
    clusterChanged = True  # 用来判断聚类是否已经收敛
    while clusterChanged:
        clusterChanged = False
        for i in range(m):  # 把每一个数据点划分到离它最近的中心点
            minDist = inf
            minIndex = -1
            for j in range(k):
                distJI = distMeans(centroids[j, :], dataSet[i, :])
                if distJI < minDist:
                    minDist = distJI
                    minIndex = j  # 如果第i个数据点到第j个中心点更近,则将i归属为j
            if clusterAssment[i, 0] != minIndex:
                clusterChanged = True  # 如果分配发生变化,则需要继续迭代
            clusterAssment[i, :] = minIndex, minDist  # 并将第i个数据点的分配情况存入字典
        for i in range(m):
            if clusterAssment[i, 0] == 0:
                plt.plot(dataSet[i, 0], dataSet[i, 1], 'ro', c='#00FF00')
            if clusterAssment[i, 0] == 1:
                plt.plot(dataSet[i, 0], dataSet[i, 1], 'ro', c='#0066FF')
            if clusterAssment[i, 0] == 2:
                plt.plot(dataSet[i, 0], dataSet[i, 1], 'ro', c='#FF0000')
            if clusterAssment[i, 0] == 3:
                plt.plot(dataSet[i, 0], dataSet[i, 1], 'ro', c='#FFCC00')
        plt.plot(centroids[:, 0], centroids[:, 1], 'ro', c='#000000')
        plt.xlim((-6, 6))
        plt.ylim((-6, 6))
        plt.show()
        for cent in range(k):  # 重新计算中心点
            ptsInClust = dataSet[nonzero(clusterAssment[:, 0].A == cent)[0]]  # 去第一列等于cent的所有列
            centroids[cent, :] = mean(ptsInClust, axis=0)  # 算出这些数据的中心点
    return centroids, clusterAssment


if __name__ == '__main__':
    datMat = mat(loadDataSet('testSet.txt'))
    myCentroids, clustAssing = kMeans(datMat, 4)
    print(myCentroids)
    print(clustAssing)

运行结果
经过4次迭代,便得到分组。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值