机器学习——KMeans聚类(机器学习实战)

483 阅读2分钟

「这是我参与11月更文挑战的第2天,活动详情查看:2021最后一次更文挑战

KMeans聚类算法

聚类是一种无监督学习,它将相似的对象归到同一个簇中。聚类方法几乎可以应用于所有对象,簇内的对象越相似。聚类的效果越好。KMeans聚类又称为k均值聚类。之所以称为K均值是因为它可以发现k个不同的簇,且每个簇的中心采用簇中所含均值计算而成。(更多细节请参考其他文章,本文只用代码实现一个例子,适合了解原理的用户观看)

实战

给一些二维数据,将这些数据分类,使用matplotlib显现出来。 我所使用的数据如下:

1.78 4.58

-3.25 3.12

4.34 -1.15

-5.77 -3.36

0.97 2.32

-3.67 1.53

0.45 -3.10

-3.49 -1.72

2.67 1.79

-3.16 3.59

存储在test.txt文件中。 我们不使用sklearn库解决,我将使用《机器学习实战》一书中的代码实现

第一步:抽取数据

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

# 加载数据
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均值聚类

# 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)  # 对矩阵的行求均值
    return centroids, clusterAssment

第四步:使用matplotlib画出。

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)

结果

QQ浏览器截图20211110222217.png

我选择了四个簇,但计算可能不准确,最终可能会画出三个簇。 k均值聚类中的簇的数目k是一个用户预先定义的参数,但用户的k值选择往往不正确。如果出现k均值算法收敛但聚类效果差的原因是,k均值算法收敛到了局部最小值,而不是全局最小值。度量聚类效果的指标是SSE(误差平方和),SSE值越小表示数据点越接近他们的质心,聚类效果越好。如何不减少簇数而又降低SSE值,就需要用到二分K均值算法。感兴趣的用户可自行了解。