《机器学习实战》学习笔记-[13]-无监督学习-利用K-均值聚类对未标注数据分组

《机器学习实战》学习笔记-[13]-无监督学习-利用K-均值聚类对未标注数据分组

一、基础

(1)聚类

       一种无监督的分类学习(unsupervised classification)在不知道目标已知分类的(这正是与分类的最大不同)的前提下,将相似对象归到同一个类簇中。其中相似的度量需要相应的相似度计算方法。备注:无监督学习不需要训练过程

(2)K-均值聚类

      寻找给定数据集的K个簇的算法,其中K是用户给定的,簇由质心(centroid,即簇中所有点的中心)描述。

  • 优点:易于实现
  • 缺点:可能收敛到局部最小值,在数据量大时收敛慢
  • 数值类型:数值型
(3)算法流程
  1. 随机选择k个初识点作为质心
  2. 将数据集中的每个点分配到一个簇中(为每个点找到其最近的质点,“最近”的度量需要距离计算方法,比如欧式距离,其他距离可参考:机器学习中的各种距离
  3. 每个簇的质心更新为该簇中所有点的均值
  4. 若本轮中有点的簇分配发生改变,重复2,直到所有点不再变化
备注这里随机选择可以在每一维度(特征)下,先计算改特征的最大和最小值,在此范围内随机产生K个值最为K个随机点该特质的取值
例如:
【[1(min),2,3]
    。。。。
    [2(max),3,4]】
对于第一个特征取1到2之间的K个随机数作为随机质点的第一列

伪代码如下:
创建K个点作为初始的质点(一般随机选择)
当任意一个点的簇分配结果发生变化:(也就是直到所有点的簇分配不再变化结束循环)
	对于数据中每个数据点
		对每个质心
			计算质心与数据点之间的距离
		将数据分配到距离最近的簇
	对每个簇,利用本簇中所有点的均值作为新的质心

(4)前面提到缺点:可能收敛到局部最小值,在数据量大时收敛慢,如何度量聚类的效果呢
  • 为此,对于每个点的所属簇的结果以如下结构存储,对于每个点:[记录所属簇的序号,该点与簇质点的距离平方也叫误差平法和SSE(Sum of Squared Error)]。其中SSE值越小表示数据点越接近质心。
  • 当SSE很大时,将最大SSE所在簇的点过滤出来,对这些点进行K=2的K-均值聚类,此时为保持K值不变,可以合并某两个簇
  • 簇合并原则具体见(5)
(5)簇合并
  • 方法1:合并最近质心
  • 方法2:合并两个使得SSE增幅最小的质心(合并所有两两簇并计算SEE,取最佳)

二、实现

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

def loadDataSet(filename):
    dataMat = []
    fr = open(filename)
    for line in fr.readlines():
        curLine = line.strip().split('\t')
        fltLine = list(map(float, curLine))  # 转为浮点数存储
        dataMat.append(fltLine)
    return dataMat


# 计算两个点间的欧式距离
def distEclud(vecA, vecB):
    return sqrt(sum(power(vecA - vecB,2)))


# 随机质点生成
def randCent(dataSet, k):
    n = shape(dataSet)[1]  # 列数,也即特征的个数
    centroids = mat(zeros((k, n)))  # k行,n维
    for j in range(n):  # 对每一特征维度 求随机数
        minJ = min(dataSet[:, j])
        rangeJ = float(max(dataSet[:, j]) - minJ)
        centroids[:,j] = mat(minJ + rangeJ * random.rand(k,1))
    return centroids

def kMeans(dataSet,k,distMeans = distEclud, createCent = randCent):
    m = shape(dataSet)[0] #待分簇的数据个数
    clusterAssment = mat(zeros((m, 2))) #m个数据点的分类簇结果
    #其中第一列是簇编号,第二列是SSE
    #产生随机k质点
    centroids = createCent(dataSet,k)
    #直到所有点不能再改变簇
    clusterChanged = True
    cnt = 0
    while clusterChanged:
        clusterChanged = False
        cnt = cnt + 1
        print(cnt)
        #对于每个点
        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
            # 判断本次循环,改点是否所属簇改变
            if clusterAssment[i, 0] != minIndex:
                clusterChanged = True
            # 更新簇信息(不分区是否改变)
            clusterAssment[i, :] = minIndex, minDist ** 2
        for centItr in range(k):  # recalculate centroids
            ptsClust = dataSet[nonzero(clusterAssment[:, 0].A == centItr)[0]]
            centroids[centItr, :] = mean(ptsClust, axis=0)  # 对列(本特质维度)求均值
    return centroids, clusterAssment


def showCluster(dataSet, k, centroids, clusterAssment):
    numSamples, dim = dataSet.shape
    if dim != 2:
        print("Sorry! I can not draw because the dimension of your data is not 2!")
        return 1

    mark = ['or', 'ob', 'og', 'ok', '^r', '+r', 'sr', 'dr', '<r', 'pr']
    if k > len(mark):
        print("Sorry! Your k is too large! please contact Zouxy")
        return 1

    # draw all samples
    for i in range(numSamples):
        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']
    # draw the centroids
    for i in range(k):
        plt.plot(centroids[i, 0], centroids[i, 1], mark[i], markersize=12)

    plt.show()

测试:
import os
from numpy import *
from ML_Learn.com.ML.Cluster.kMeans import kMeans
#导入训练数据集
inputMat = mat(kMeans.loadDataSet(os.getcwd() + '/resource/testSet.txt'))
centroids,clusterAssment = kMeans.kMeans(inputMat,4)
print("centroids:\n",centroids)
print("clusterAssment:\n",clusterAssment)
kMeans.showCluster(inputMat, 4, centroids, clusterAssment)

5次循环后:

1
2
3
4
5
centroids:
 [[-2.46154315  2.78737555]
 [ 2.6265299   3.10868015]
 [-3.53973889 -2.89384326]
 [ 2.65077367 -2.79019029]]
clusterAssment:
 [[  1.           2.3201915 ]
 [  0.           1.39004893]
 [  3.           7.46974076]
 [  2.           3.60477283]
 [  1.           2.7696782 ]
 [  0.           2.80101213]
 [  3.           5.10287596]
。。。。。。



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值