K-means聚类算法
简述
聚类是指将数据划分成多个组的任务,每一个组都叫做簇。聚类的目标就是要划分数据,使得每一个组里面的元素非常相似,但不同组里面的数据又非常不同,简单来说就是叫分类。我们通过聚类可以很方便地让我们对数据进行处理,把相似的数据分成一类,从而可以使得数据更加清晰。
K-means是聚类算法中最典型的一个,也是最简单、最常用的一个算法之一。这个算法主要的作用是将相似的样本自动归到一个类别中。通过设定合理的 K K K值,能够决定不一样的聚类效果。
K-means算法原理与理解
基本原理
假定给定数据样本 X X X,包含了 n n n个对象 X = { X 1 , X 2 , X 3 , . . . , X n } X=\{X_1,X_2,X_3,...,X_n\} X={X1,X2,X3,...,Xn},其中每个对象都具有m个维度的属性。Kmeans算法的目标是将n个对象依据对象间的相似性聚集到指定的 k k k个类簇中,且每个对象到类簇中心距离最小。
算法流程
主要思想:在给定
k
k
k值和
k
k
k个初始类簇中心点的情况下,把每个点分到离最近的类簇中心点所代表的类簇中,所有点分配完毕之后,根据一个类簇内所有点的到类簇中心的距离的平均值,然后多次迭代进行点的分配和类簇中心点的更新。
那么,我们首先初始化
k
k
k个聚类中心
{
C
1
,
C
2
,
C
3
,
.
.
.
,
C
k
}
,
1
<
j
≤
n
\{C_1,C_2,C_3,...,C_k\},1<j\leq n
{C1,C2,C3,...,Ck},1<j≤n。然后计算每一个对象到每一个聚类中心的欧氏距离
d
i
s
(
X
i
,
C
j
)
=
∑
t
=
1
m
(
X
i
t
−
C
j
t
)
2
dis(X_i,C_j)=\sqrt{\sum^m_{t=1}(X_{it}-C_{jt})^2}
dis(Xi,Cj)=t=1∑m(Xit−Cjt)2
符号 | 说明 | 范围 |
---|---|---|
X i X_i Xi | 表示第 i i i个对象 | 1 ≤ i ≤ n 1\leq i\leq n 1≤i≤n |
C j C_j Cj | 表示第 j j j个聚类中心 | 1 ≤ j ≤ k 1\leq j\leq k 1≤j≤k |
X i t X_{it} Xit | 表示第 i i i对象的第 t t t个属性 | 1 ≤ t ≤ m 1\leq t\leq m 1≤t≤m |
C j t C_{jt} Cjt | 表示第 j j j个聚类中心的第 t t t个属性 | 1 ≤ t ≤ m 1\leq t\leq m 1≤t≤m |
算法步骤
输入:样本集D,簇的数目k,最大迭代次数N;
输出:簇划分(k个簇,使平方误差最小);
算法步骤:
(1)为每个聚类选择一个初始聚类中心;
(2)将样本集按照最小距离原则分配到最邻近聚类;
(3)使用每个聚类的样本均值更新聚类中心;
(4)重复步骤(2)、(3),直到聚类中心不再发生变化;
(5)输出最终的聚类中心和k个簇划分;
K-Means算法优缺点
-
优点
(1)原理易懂、易于实现;
(2)当簇间的区别较明显时,聚类效果较好; -
缺点
(1)当样本集规模大时,收敛速度会变慢;
(2)对孤立点数据敏感,少量噪声就会对平均值造成较大影响;
(3)k的取值十分关键,对不同数据集,k选择没有参考性,需要大量实验
代码实现
# -*- coding: utf-8 -*-
#author: w61
import random
import math
import matplotlib.pyplot as plt
class Kmeans():
def __init__(self, k, mode):
self.datasets = []
self.vector = 0 #记录数据集的维数
self.k = k #聚类簇数
self.C = [[] for i in range(k)] #簇
self.mode = 0 #初始化方式
self.mean_vector = [] #均值向量
self.update_flag = 0 #记录均值向量是否改变
self.count = 0 #记录循环次数
self.max_count = 500 #最大运行轮数
def LoadData(self, file_name):
"""
读取数据集
:param file_name:数据集的路径
:return:null
"""
with open(file_name) as f:
for contents in f:
contents = contents.replace('\n','')
content = contents.split(' ')
self.datasets.append(content[1:])
self.vector = len(self.datasets[0])
def Inialize(self):
"""
初始化均值向量
:return:null
"""
if self.mode == 0:
means = random.sample(range(0,len(self.datasets)),self.k)
for mean in means:
self.mean_vector.append(self.datasets[mean])
def getDistance(self, x, y):
"""
计算两个向量(x和y)之间的距离
:param x:
:param y:
:return: dis 距离
"""
dis = 0
for i in range(self.vector):
dis += pow((float(x[i])-float(y[i])),2)
dis = math.sqrt(dis)
return dis
def Clustering(self):
"""
划分簇
:return:null
"""
self.C = [[] for m in range(self.k)] #每一次都要先把C置零
for j in range(0, len(self.datasets)):
min_dis = 0
min_index = 0
for i in range(self.k):
dis = self.GetDistance(self.datasets[j],self.mean_vector[i])
if min_dis == 0 or dis < min_dis:
min_dis = dis
min_index = i
self.C[min_index].append(j)
def Update(self):
"""
更新每个簇的均值向量
:return:
"""
self.update_flag = 0
for i in range(self.k):
means= []
for h in range(self.vector):
sum = 0
for j in self.C[i]:
sum += float(self.datasets[j][h])
if len(self.C[i]) == 0:
mean = 0
else:
mean = sum / len(self.C[i])
means.append(mean)
if means == self.mean_vector[i]:
continue
else:
self.mean_vector[i] = list(means)
self.update_flag = 1
def Plot(self):
"""
绘图
:return:
"""
fig = plt.figure()
ax = fig.add_subplot(111)
colors = ['red','blue','green','black','pink','brown','gray']
for i in range(self.k):
for j in self.C[i]:
x = float(self.datasets[j][0])
y = float(self.datasets[j][1])
plt.scatter(x,y,color = colors[i],marker='+')
for i in range(self.k):
for j in self.mean_vector:
x = float(j[0])
y = float(j[1])
plt.scatter(x,y,color = 'cyan',marker='p')
plt.show()
def Process(self):
"""
执行函数
:return:
"""
self.LoadData('data.txt')
self.Inialize()
while self.count <= self.max_count:
self.Clustering()
self.Update()
if self.update_flag == 0:
break
self.count += 1
print('k-means分类结果如下:')
print(self.C)
self.Plot()
if __name__ == "__main__":
kmeans = Kmeans(5, 0)
kmeans.Process()
测试所用的数据
1 0.697 0.460
2 0.774 0.376
3 0.634 0.264
4 0.608 0.318
5 0.556 0.215
6 0.403 0.237
7 0.481 0.149
8 0.437 0.211
9 0.666 0.091
10 0.243 0.267
11 0.245 0.057
12 0.343 0.099
13 0.639 0.161
14 0.657 0.198
15 0.360 0.370
16 0.593 0.042
17 0.719 0.103
18 0.359 0.188
19 0.339 0.241
20 0.282 0.257
21 0.748 0.232
22 0.714 0.346
23 0.483 0.312
24 0.478 0.437
25 0.525 0.369
26 0.751 0.489
27 0.532 0.472
28 0.473 0.376
29 0.725 0.445
30 0.446 0.459