1.聚类
聚类:简而言之就是物以类聚,与分类不同的是,对目标是未知的。它是一种无监督的学习(Unsupervised Learning)方法,不需要预先标注好的训练集。
分类:目标类别已知,对数据进行归类。
2.K-Means 算法
kmeans算法又名k均值算法。其算法思想大致为:先从样本集中随机选取 k个样本作为簇中心,并计算所有样本与这 k个“簇中心”的距离,对于每一个样本,将其划分到与其距离最近的“簇中心”所在的簇中,对于新的簇计算各个簇的新的“簇中心”。
根据以上描述,我们大致可以猜测到实现kmeans算法的主要三点:
(1)簇个数 k的选择 (2)各个样本点到“簇中心”的距离 (3)根据新划分的簇,更新“簇中心”
2.1瓜的分类
现在有一批数据,西瓜的甜度和水分。
甜度 | 水分 |
---|---|
1.658985 | 4.285136 |
3.453687 | 3.424321 |
4.838138 | 1.151539 |
… | … |
可以对这些西瓜来进行一个聚类,数据展示如下:
1.产生K个随机质心
# 为给定数据集构建一个包含 k 个随机质心的集合。随机质心必须要在整个数据集的边界之内,这可以通过找到数据集每一维的最小和最大值来完成。然后生成 0~1.0 之间的随机数并通过取值范围和最小值,以便确保随机点在数据的边界之内。
def randCent(dataSet, k):
n = shape(dataSet)[1] # 列的数量,即数据的特征个数
centroids = mat(zeros((k,n))) # 创建k个质心矩阵
for j in range(n): # 创建随机簇质心,并且在每一维的边界内
minJ = min(dataSet[:,j]) # 最小值
rangeJ = float(max(dataSet[:,j]) - minJ) # 范围 = 最大值 - 最小值
centroids[:,j] = mat(minJ + rangeJ * random.rand(k,1)) # 随机生成,mat为numpy函数,需要在最开始写上 from numpy import *
return centroids
2.计算两个向量的欧氏距离
n维空间的公式
# 计算两个向量的欧式距离(可根据场景选择其他距离公式)
def distEclud(vecA, vecB):
return sqrt(sum(power(vecA - vecB, 2))) # la.norm(vecA-vecB)
3.K-Means 聚类算法
def kMeans(dataSet, k, distMeans=distEclud, createCent=randCent):
m = shape(dataSet)[0]
clusterAssment = mat(zeros((m, 2))) # 用于存放该样本属于哪类及质心距离
# clusterAssment第一列存放该数据所属的中心点,第二列是该数据到中心点的距离
centroids = createCent(dataSet, k)
plt.title('start', fontsize=24)
plt.xlabel('X', fontsize=14)
plt.ylabel('Y', fontsize=14)
for i in range(shape(dataSet)[0]):
plt.scatter(dataSet[i, 0], dataSet[i, 1], s=50, c='b', alpha=0.5)
for i in range(shape(centroids)[0]):
plt.scatter(centroids[i, 0], centroids[i, 1], s=50, c='r', alpha=1, marker='x')
# 设置刻度标记的大小
plt.tick_params(axis='both', which='major', labelsize=14)
plt.show()
clusterChanged = True # 用来判断聚类是否已经收敛
while clusterChanged:
clusterChanged = False
for i in range(m): # 把每一个数据点划分到离它最近的中心点
minDist = inf # 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**2 # 并将第i个数据点的分配情况存入字典
for cent in range(k): # 重新计算中心点
ptsInClust = dataSet[nonzero(clusterAssment[:, 0].A == cent)[0]] # 取第一列等于cent的所有列
centroids[cent, :] = mean(ptsInClust, axis=0) # 算出这些数据的中心点
show(dataSet, clusterAssment, centroids)
return centroids, clusterAssment
4.数据plt展示与运行
def show(dataSet, clusterAssment, centroids):
plt.title('K Means', fontsize=24)
plt.xlabel('X', fontsize=14)
plt.ylabel('Y', fontsize=14)
for i in range(shape(dataSet)[0]):
if clusterAssment[i, 0] == 0:
col = 'b'
if clusterAssment[i, 0] == 1:
col = 'c'
if clusterAssment[i, 0] == 2:
col = 'g'
if clusterAssment[i, 0] == 3:
col = 'm'
plt.scatter(dataSet[i, 0], dataSet[i, 1], s=50, c=col, alpha=0.5)
for i in range(shape(centroids)[0]):
plt.scatter(centroids[i, 0], centroids[i, 1], s=50, c='r', alpha=1, marker='x')
# 设置刻度标记的大小
plt.tick_params(axis='both', which='major', labelsize=14)
plt.show()
# 用测试数据及测试kmeans算法
datMat = mat(loadDataSet('testSet.txt'))
myCentroids, clustAssing = kMeans(datMat, 4)
# print(clustAssing)
print(myCentroids)
5.结果
3.K-Means 算法缺点
- 需手动设置k值。 在算法开始预测之前,我们需要手动设置k值,即估计数据大概的类别个数,不合理的k值会使结果缺乏解释性
- 可能收敛到局部最小值, 在大规模数据集上收敛较慢
- 对于异常点、离群点敏感