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