无监督学习算法——KMeans聚类

什么是KMeans聚类算法

K-Means是一种无监督的聚类机器学习算法;之前学习的分类算法,其数据是已经有明确的类别标识了,所以在之前的分类机器学习算法中,算法所要去学习的是如何找到一个或几个特征的组合,能够实现数据的分类操作;但是,在聚类算法中,数据到底可以分为几类是不知道的,只能让算法自行依靠某些规则或约定,对数据进行聚类操作(将可能是同一类别的数据放在一起)。

由于数据的类别我们并不清楚,所以,我们无法监督我们的算法最后的结果是好还是坏,缺乏明确的目标值——这就是无监督机器学习。K-Means算法就是一个典型的无监督机器学习算法。

K-Means算法的原理很像KNN算法,KNN算法是计算未知点到已知点的距离对未知点进行分类处理;K-Means算法则是通过在所有点中找几个中心点,进行计算其他点到各个中心点的距离,距离那个中心点进就归类到那个中心点去,在第一轮归类完后,进行计算每一类的均值,将均值点作为新的中心点,再此重复上述步骤,知道整个归类的结果不再改变时停止上述工作,将这些步骤抽出来简化下就是这样

初步选取目前类别个数,选取中心点 ——>> 计算与各个中心点的距离,聚类 <<——{如果聚类结果不再改变,结束}——>> 计算均值,重新确定中心点

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import numpy as np

def loadDataSet(fileName):
"""[训练、测试数据文件的加载]
Arguments:
fileName {[str]} -- [训练数据集]
Returns:
[list] -- [训练数据集]
"""
dataMat = []
fr = open(fileName)
for line in fr.readlines():
curLine = line.strip().strip('\t')
fltLine = map(float, curLine)
dataMat.append(fltLine)
return dataMat

def distEclud(vecA, vecB):
"""[计算各个点到中心点的距离]
Arguments:
vecA {[np.array]} -- [中心点]
vecB {[np.array]} -- [未知点]
Returns:
[double] -- [距离]
"""
return np.sqrt(np.sum(np.power(vecA - vecB, 2)))

def randCent(dataSet, k):
"""[根据dataSet构建k个随机的中心点]
Arguments:
dataSet {[list]} -- [数据集]
k {[int]} -- [聚类目标个数]
Returns:
[list] -- [中心点集合]
"""
n = np.shape(dataSet)[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, distMeans=distEclud, createCent=randCent):
"""[K-Means算法主体]
Arguments:
dataSet {[list} -- [数据集]
k {[int]} -- [目标聚类个数]
Keyword Arguments:
distMeans {[function]} -- [计算距离的方法] (default: {distEclud})
createCent {[function]} -- [产生中心点的方法] (default: {randCent})
Returns:
[tuple] -- [最终每一类的中心点与分配结果]
"""
m = np.shape(dataSet)[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 = distMeans(centroids[j, :], dataSet[i, :])
if distJI < minDist:
minDist = distJI; minIndex = j
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