美文网首页机器学习算法生信
利用K-均值聚类算法对未标注数据分组(一)

利用K-均值聚类算法对未标注数据分组(一)

作者: RossH | 来源:发表于2019-11-09 18:00 被阅读0次

    概述

    • 优点:容易实现
    • 缺点:可能收敛到局部最小值,在大规模数据集上收敛较慢
    • 适用数据类型:数值型数据

    聚类是一种无监督学习,将相似的对象归到一个簇中。K-均值(K-means)聚类算法,可以发现k个不同的簇,且每个簇的中心采用簇中所含值的均值计算而成。

    K-means聚类算法实现

    K-均值是发现给定数据集的k个簇的算法,k由用户给定。

    K-means算法工作流程:

    1. 随机选定k个初始点作为质心(即簇中所有点的中心)
    2. 为数据集中每个点找到距其最近的质心,并将其分配到该质心所对应的簇
    3. 每个簇的质心更新为该簇所有点的平均值

    伪代码如下:

    随机选择k个点作为初始质心
    当任意一个点的簇分配结果发生改变时:
        对数据集中的每个数据点:
            对每个质心:
                计算质心与数据点之间的距离
            将数据点分配到距其最近的簇
        对每一个簇,计算簇中所有点的均值并将其作为质心
    

    代码实现:

    import numpy as np
    
    # 加载数据集
    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 np.sqrt(np.sum(np.power(vecA - vecB, 2)))
    
    # 随机质心
    def randCent(dataSet, k):
        n = dataSet.shape[1]
        centroids = np.mat(np.zeros((k,n)))
        for j in range(n):
            minJ = min(dataSet[:, j])
            rangeJ = float(max(dataSet[:, j]) - minJ)
            centroids[:, j] = minJ + rangeJ * np.random.rand(k, 1)
        return centroids
    
    def kMeans(dataSet, k, distMeas=distEclud, createCent=randCent):
        m = dataSet.shape[0]
        clusterAssment = np.mat(np.zeros((m,2)))     # 用于记录聚类
        centroids = createCent(dataSet, k)
        clusterChanged = True
        while clusterChanged:
            clusterChanged = False
            # 遍历所有点
            for i in range(m):
                minDist = np.inf
                minIndex = -1
                # 寻找最近的质心
                for j in range(k):
                    distJI = distMeas(centroids[j,:], dataSet[i,:])
                    if distJI < minDist:
                        minDist = distJI
                        minIndex = j
                # 点所属簇发生改变的话将clusterChanged改为True
                if clusterAssment[i, 0] != minIndex:
                    clusterChanged = True
                clusterAssment[i, :] = minIndex, minDist ** 2
            print(centroids)
            # 更新质心的位置
            for cent in range(k):
                ptsInClust = dataSet[np.nonzero(clusterAssment[:,0].A == cent)[0]]
                centroids[cent, :] = np.mean(ptsInClust, axis=0)
        return centroids, clusterAssment
    

    kMeans()函数接受4个输入函数,只有数据集及簇的数目是必需的,而用来计算距离和创建初始随机质心的函数都是可选的。

    簇分配结果矩阵clusterAssment包含两列:一列记录簇索引值,第二列存储误差。这里的误差指当前点到簇质心的距离,后面会用来评价聚类效果。

    接下来用一个数据集来展示一下。

    data = np.mat(loadDataSet('testSet.txt'))
    myCentroids, clustAssing = kMeans(data, 4)
    

    输出如下:

    [[ 0.58416761  4.95307752]
     [ 1.65859849 -0.32066583]
     [-3.08249088  0.60763474]
     [-2.3709823  -3.100304  ]]
    [[ 1.75060988  3.63551582]
     [ 3.05395587 -1.49072096]
     [-2.65218135  2.62294929]
     [-3.01169468 -3.01238673]]
    [[ 2.54391447  3.21299611]
     [ 2.8692781  -2.54779119]
     [-2.46154315  2.78737555]
     [-3.38237045 -2.9473363 ]]
    [[ 2.6265299   3.10868015]
     [ 2.80293085 -2.7315146 ]
     [-2.46154315  2.78737555]
     [-3.38237045 -2.9473363 ]]
    

    一共输出4次质心,也就是说,经过4次迭代后kMeans算法收敛。

    下图是数据集聚类结果的可视化,簇中心用十字表示。


    相关文章

      网友评论

        本文标题:利用K-均值聚类算法对未标注数据分组(一)

        本文链接:https://www.haomeiwen.com/subject/acpnbctx.html