k-means (k均值) 聚类算法 小结

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zaishuiyifangxym/article/details/89488420

目录

1 聚类简介

2 k-means算法流程

3 利用k-means 对数据进行聚类

4 利用K-means进行图像分割

5 小结

参考资料


1 聚类简介

在无监督学习中,训练样本的标记信息是未知的,我们的目标是通过对无标记训练样本的学习来解释数据的内在性质及规律,为了进一步的数据分析提供基础,此类学习应用最多的就是“聚类”(clustering)。

聚类(clustering) 就是视图将数据集中的样本划分为若干个互不相交的子集,每个子集称为一个簇(cluster)。通过这样的划分,每个簇可能对应于一些潜在的类别,如有一堆瓜,分为:有籽瓜和无籽瓜 或者 浅色瓜和深色瓜 或进口瓜和国产瓜 等分类。注意:这些概念对聚类算法而言是实现位置的,聚类过程是自动形成簇结构。

使用数学语言描述聚类为:假设有样本集 D = \{ {{\bf{x}}_1},{{\bf{x}}_2}, \ldots ,{{\bf{x}}_m}\}包含 m个无标记样本,每个样本{{\bf{x}}_i} = {({x_{i1}},{x_{i1}}, \ldots ,{x_{in}})^T} 是一个n维的特征向量,则聚类算法需要将样本集 D 划分为 k 各互不相交的簇\{ {C_l}\left| {l = 1,2, \ldots ,k} \right.\} ,其中{C_{l'}}{ \cap _{l' \ne l}}{C_l} = \emptysetD = \cup _{l = 1}^k{C_l} 。相应的,我们用{\lambda _j} \in \{ 1,2, \ldots ,k\} 表示样本 {{\bf{x}}_j}的“簇标记”(cluster label),即 {{\bf{x}}_j} \notin {C_{{\lambda _j}}}。于是,聚类的结果可用包含m个元素的簇标记向量{\bf{\lambda }} = {({\lambda _1},{\lambda _2}, \ldots ,{\lambda _m})^T} 表示。

当看完这个数学描述时,心中默念:啥啥啥,这写的是啥。

扫描二维码关注公众号,回复: 6113458 查看本文章

其实,聚类没有那么难,上面的数学描述看着挺吓人的,其实通过简单地例子来说明,就基本理解了。下面就介绍经典的聚类算法——k-means (k均值)。​​​​

k-means是最简单的聚类算法之一,应用十分广泛,k-means以距离作为相似性的评价指标,其基本思想是按照距离将样本聚成不同的簇,两个点的距离越近,其相似度就越大,以得到紧凑且独立的簇作为聚类目标。

 

2 k-means算法流程

下面是k-means的算法流程:


输入:样本集D = \{ {{\bf{x}}_1},{{\bf{x}}_2}, \ldots ,{{\bf{x}}_m}\}
           聚类簇数 k


过程:
1:从D随机选择k个样本作为初始均值向量 \{ {{\bf{\mu }}_1},{{\bf{\mu }}_2}, \ldots ,{{\bf{\mu }}_k}\}
2:repeat
3:    令 {C_i} \ne \emptyset {\rm{ }}(1 \le i \le k)
4:    for j = 1,2, \ldots ,m  do
5:     计算样本 {{\bf{x}}_j}与个均值向量 {{\bf{\mu }}_i}{\rm{ }}(1 \le i \le k)的距离:{d_{ji}} = {\left\| {{{\bf{x}}_j} - {{\bf{\mu }}_i}} \right\|_2}


6:     根据样本距离最近的均值向量确定{{\bf{x}}_j} 的簇标记:{{\bf{\lambda }}_j} = \mathop {\arg \min }\limits_{i \in \{ 1,2, \ldots ,k\} } {\rm{ }}{d_{ji}}
7:     将样本 {{\bf{x}}_j}划入相应的簇:{C_{{{\bf{\lambda }}_j}}} = {C_{{{\bf{\lambda }}_j}}} \cup \{ {{\bf{x}}_j}\}
8: end for

9:    for  i = 1,2, \ldots ,k do


10:   计算新均值向量: \mathbf{\mu }_{i}^{'}=\frac{1}{\left| {{C}_{i}} \right|}\sum\limits_{x\in {{C}_{i}}}{\mathbf{x}}
11:        if   \mathbf{\mu }_{i}^{'}\ne {{\mathbf{\mu }}_{i}} then
12:                将当前均值向量{{\bf{\mu }}_i} 更新为 {\bf{\mu }}_i^'
13:        else
14:                 保持当前均值向量不变
15:        else if 
16:    end for
17:until 当前均值向量均未更新


输出:簇划分  C = \{ {C_1},{C_2}, \ldots ,{C_k}\}


直接看算法,一时半会很难理解,直接用实际数据一步步计算,更直观,下面用实际的数据进行实验。

 

3 利用k-means 对数据进行聚类

实验数据使用 周志华-机器学习 中的 西瓜数据集4.0 ,如表1所示:

表1 西瓜数据集4.0

编号

密度

含糖率

1

0.679

0.460

2

0.744

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.567

0.198

15

0.360

0.370

16

0.593

0.042

17

0.719

0.103

18

0.387

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

 

使用上面的数据集,假设现在需要聚类簇数 k=3。
(1)首先随机选取三个样本 {{\bf{x}}_6},{{\bf{x}}_{12}},{{\bf{x}}_{27}}(编号为6,12,27对应的数据)作为初始均值向量,即:

{{\bf{\mu }}_1}=(0.403;0.237),  {{\bf{\mu }}_2}=(0.343;0.099),  {{\bf{\mu }}_2}=(0.532;0.472)

(2)将第一个样本 {{\bf{x}}_1}=(0.697;0.460)与当前的均值向量 {{\bf{\mu }}_1},{{\bf{\mu }}_2},{{\bf{\mu }}_3}计算他们之间的距离,距离结果为:0.369,0.506,0.166,因此第一个样本{{\bf{x}}_1} 被划入到簇{C_3} 中。同样的,对数据集中的所有样本就进行计算,可得到当前簇划分为:

 {C_1} = \{ {{\bf{x}}_5},{{\bf{x}}_6},{{\bf{x}}_7},{{\bf{x}}_8},{{\bf{x}}_9},{{\bf{x}}_{10}},{{\bf{x}}_{13}},{{\bf{x}}_{14}},{{\bf{x}}_{15}},{{\bf{x}}_{17}},{{\bf{x}}_{18}},{{\bf{x}}_{19}},{{\bf{x}}_{20,}}{{\bf{x}}_{23}}\}

 {C_2} = \{ {{\bf{x}}_{11}},{{\bf{x}}_{12,}}{{\bf{x}}_{16}}\}

 {C_3} = \{ {{\bf{x}}_1},{{\bf{x}}_2},{{\bf{x}}_3},{{\bf{x}}_4},{{\bf{x}}_{21}},{{\bf{x}}_{22}},{{\bf{x}}_{24}},{{\bf{x}}_{25}},{{\bf{x}}_{26}},{{\bf{x}}_{27}}{{\bf{x}}_{28}},{{\bf{x}}_{29}},{{\bf{x}}_{30}}\}

 

(3){C_1},{C_2},{C_3} 中分别计算新的均值向量

 {\mathbf{\mu }}_1^'=(0.473;0.214), {\bf{\mu }}_2^'=(0.394;0.066), {\bf{\mu }}_2^'=(0.623;0.388)

 

(4)重新进入(2)和(3),不断重复,知道当前的均值向量保持不变,即可停止。

分类的结果如下图所示:

 

下面是k-means聚类使用的Matlab代码

clear all;clc;tic;

X=[0.679,0.460;
   0.744,0.376;
   0.634,0.264;
   0.608,0.318;
   0.556,0.215;
   0.403,0.237;
   0.481,0.149;
   0.437,0.211;
   0.666,0.091;
   0.243,0.267;
   0.245,0.057;
   0.343,0.099;
   0.639,0.161;
   0.567,0.198;
   0.360,0.370;
   0.593,0.042;
   0.719,0.103;
   0.387,0.188;
   0.339,0.241;
   0.282,0.257;
   0.748,0.232;
   0.714,0.346;
   0.483,0.312;
   0.478,0.437;
   0.525,0.369;
   0.751,0.489;
   0.532,0.472;
   0.473,0.376;
   0.725,0.445;
   0.446,0.459];

k=3;
[Idx,Ctrs,SumD,D]=kmeans(X,k);


%画出聚类为1的点。
%X(Idx==1,1),为第一类的样本的第一个坐标;
%X(Idx==1,2)为第二类的样本的第二个坐标
plot(X(Idx==1,1),X(Idx==1,2),'r.','MarkerSize',14)
hold on
plot(X(Idx==2,1),X(Idx==2,2),'b.','MarkerSize',14)
hold on
plot(X(Idx==3,1),X(Idx==3,2),'g.','MarkerSize',14)

%绘出聚类中心点,kx表示是圆形
plot(Ctrs(:,1),Ctrs(:,2),'kx','MarkerSize',14,'LineWidth',4)
plot(Ctrs(:,1),Ctrs(:,2),'kx','MarkerSize',14,'LineWidth',4)
plot(Ctrs(:,1),Ctrs(:,2),'kx','MarkerSize',14,'LineWidth',4)

legend('Cluster 1','Cluster 2','Cluster 3','Centroids','Location','NW')

toc;

 

下面简单介绍Matlab 中 kmeans 函数如何使用:

kmeans 函数使用方法:


Idx=kmeans(X,K) 

[Idx,C]=kmeans(X,K) 

[Idx,C,sumD]=kmeans(X,K) 

[Idx,C,sumD,D]=kmeans(X,K) 

[…]=kmeans(…,’Name1’,Value1,’Name2’,Value2,…)


函数中,输入和输出参数的介绍:

X:数据为N\timesP维度的矩阵;

K:表示将X划分为几类,为整数;

Idx:N\times1的向量,存储的是每个点的聚类标号;

C:K\timesP的矩阵,存储的是K个聚类质心位置;

sumD:1\timesK的和向量,存储的是类间所有点与该类质心点距离之和;

D:N\timesK的矩阵,存储的是每个点与所有质心的距离;

 

[…]=kmeans(…,’Name1’,Value1,’Name2’,Value2,…);

这个用法可以查看 Matlab kmeans 帮助文档,这里简单介绍一下:Distance (距离测度) 和 Start (初始质心位置选择方法)
      主要可以设置为如下:
      1)‘Distance’:(距离测度),value如下:

‘sqEuclidean’ :欧式距离(默认时,采用此距离方式);

 ‘cityblock’ :绝度误差和,又称:L1;

 ‘cosine’ :针对向量;

‘correlation’  :针对有时序关系的值; 

‘Hamming’ :只针对二进制数据;

Example: 'Distance','cityblock'


      2) ‘Start’:初始质心位置选择方法,value如下:

‘sample’:从X中随机选取K个质心点;

‘uniform’: 根据X的分布范围均匀的随机生成K个质心;

‘cluster’: 初始聚类阶段随机选择10%的X的子样本(此方法初始使用’sample’方法;

Example: 'start','sample'

还有其他的参数设置,可以参见Matlab kmeans 帮助文档 


 

4 利用K-means进行图像分割

下面是利用K-means进行图像分割的Matlab 代码:

clear all;clc;tic;

C_Segments=2;%聚类的个数

img_original = imread('lena.tiff');%读入图像
figure,imshow(img_original),title('原始图像');    %显示原图像
img_gray=rgb2gray(img_original);
figure,imshow(img_gray),title('原始灰度图像');

% 获取图像的长宽
[m,n]=size(img_gray);

% 灰度阈值计算
T=graythresh(img_gray);
img_bw=im2bw(img_gray,T);
figure,imshow(img_bw),title('原始二值图像');

% 将图像进行RGB——3通道分解
R = reshape(img_original(:, :, 1), m*n, 1);  % 将R分量各转为kmeans使用的数据格式m*n=512*512=262144行
G = reshape(img_original(:, :, 2), m*n, 1);  % 将G分量各转为kmeans使用的数据格式m*n=512*512=262144行
B = reshape(img_original(:, :, 3), m*n, 1);  % 将B分量各转为kmeans使用的数据格式m*n=512*512=262144行
dat = [R,G,B];  % r g b分量组成样本的特征,每个样本有三个属性值,共width*height个样本()
cRGB = kmeans(double(dat), C_Segments,'Distance','city', 'emptyaction','singleton','start','sample');  % 使用聚类算法分为2类

rRGB = reshape(cRGB, m, n);     % 反向转化为图片形式
figure, imshow(label2rgb(rRGB)),title('RGB通道分割结果');   % 显示分割结果


% 将图像进行单一通道灰度分解
GraySeg= reshape(img_gray(:, :), m*n, 1);
cGray=kmeans(double(GraySeg), C_Segments);
rGray= reshape(cGray, m, n);     % 反向转化为图片形式
figure, imshow(label2rgb(rGray)),title('灰度图分割结果');   % 显示分割结果

toc;

 

分类结果如下图所示:

 

 

5 小结

k-means聚类算法的实现过程大致表示如下:

(1) 随机选取k个初始聚类中心; 

(2) 计算每个样本到各聚类中心的距离,将每个样本归到其距离最近的聚类中心; 

(3) 对每个簇,以所有样本的均值作为该簇新的聚类中心; 

(4) 重复第(2)~(3)步,直到聚类中心不再变化或达到设定的迭代次数。 

 

参考资料

[1] https://blog.csdn.net/mrharvey/article/details/18085163

[2] https://blog.csdn.net/jteng/article/details/48811881

[3] https://blog.csdn.net/google19890102/article/details/52911835

[4] https://blog.csdn.net/mingtian715/article/details/51534165

[5] https://blog.csdn.net/a493823882/article/details/79282425

[6] Matlab kmeans 帮助文档

[7] 周志华 著. 机器学习, 北京: 清华大学出版社, 2016年1月.

 

猜你喜欢

转载自blog.csdn.net/zaishuiyifangxym/article/details/89488420