聚类是一种数据分析方法,针对已有的数据根据挑选的特征将其分为多类,特征最相似的几种特征归为一类。俗话说的“人以类聚,物以群分”说的就是这个道理,只不过聚类将这种道理从理论的角度来进行阐释和升华,聚类可以用于分类任务中,属于机器学习中的无监督学习。这里主要根据我模式识别所做的课程作业,简单介绍K聚类,fuzzy-C聚类,以及GMM聚类。
- K-means 聚类方法
其中K指的是聚类的数目,聚类方法的核心思路如下:
- 确定聚类中心数目
- 确定聚类中心更新策略
- 确定聚类停止条件或者设置迭代上限
对于K聚类来说算法流程如下:
首先初始化K个聚类中心:
初始化的方法我选用的是随机从数据样本中选用K个点的特征作为K个聚类初始中心,以利用二维的数据特征为例(方便画图,直观形象的展现出来),下图中蓝色的点就是数据点在特征空间的展示,黑色的叉就是随机初始化的3个聚类中心所在.
图 1 初始化聚类中心
聚类中心更新:
遍历所有点,将样本点Xi归类为距离最近的类,这样我们就能得到每一类的子集:
设样本集为:
其特征为(x1,x2)二维的特征。根据样本与各聚类中心距离远近可以将样本归到不同的类,得到每一类的样本集
然后根据如下公式,平均各点特征作为新的聚类中心:
废话不多说,上一个例程就全都懂了。
<code :>
%%sunyi
%%K聚类的方法就是初始化K类中心然后不断更新的过程,用的是欧式距离
clc;
clearvars;
close all;
k=3;%确定聚类的个数
num=50;%确定点的数据
sigma=1;
for i=1:k
class(i)=struct('x',i*10,'y',10*i*10);
end
figure;
hold on;
count=0;
for i=1:k
x=ones(num,1)*class(i).x+randn(num,1)*10;
y=ones(num,1)*class(i).y+randn(num,1)*10;
X(count+1:count+num,1)=x;
X(count+1:count+num,2)=y;
count=count+num;
plot(x,y,'b*');
end
%%
% %kmeans
% [idx,C]=kmeans(X,3);
% plot(C(:,1),C(:,2),'bx','MarkerSize',15,'LineWidth',5);
%%
Cen=zeros(k,2);
%随机初始化聚类中心
for i=1:k
n=floor(rand()*count);
Cen(i,1)=X(n,1);
Cen(i,2)=X(n,2);
end
plot(Cen(:,1),Cen(:,2),'kx','MarkerSize',15,'LineWidth',3);
flag=1;
while(flag)
record=zeros(k,2);
recordcount=zeros(k,1);
for i=1:count
dis(1)=(X(i,1)-Cen(1,1))^2+(X(i,2)-Cen(1,2))^2;%计算样本点与聚类中心的距离
dis(2)=(X(i,1)-Cen(2,1))^2+(X(i,2)-Cen(2,2))^2;
dis(3)=(X(i,1)-Cen(3,1))^2+(X(i,2)-Cen(3,2))^2;
[M,I]=min(dis);%归为最近的一类中
record(I,1)=record(I,1)+X(i,1);
record(I,2)=record(I,2)+X(i,2);
recordcount(I,1)=recordcount(I,1)+1;
end
new_Cen=record./recordcount;
dif=abs(new_Cen-Cen)<0.1;
[M,N]=find(dif==1);
nn=size(M);
Cen=new_Cen;
if nn(1,1)==k*2%如果迭代更新趋缓,则停止更新,聚类结束
break;
end
end
plot(Cen(:,1),Cen(:,2),'rx','MarkerSize',15,'LineWidth',3);%打印最终的聚类中心
%%
2. fuzzy-C聚类
k聚类是一种硬聚类,即一个样本属于不可能属于两个类,而软聚类是以概率衡量每一个样本点对每一类的归属度,这样在更新各个聚类中心的时候,样本点以其对于每一类的归属度作为权重,在更新权重时做出相应大小的贡献。只要弄清楚中心更新的思路之后,对于Fuzzy-C的应用来说就完全够了:
元素 j 对第 i 类的隶属度(u为隶属度矩阵,d为闵科夫斯基距离,b为模糊系数),其实简化之后就是将元素j与所有类的距离做了一个计算之后然后归一化,使之成为一个概率分布(拙见):
图 2 隶属度计算
更新m为第j类新的中心,u为隶属度矩阵,uij代表的就是元素xi 属于类j的概率,c为聚类中心的总数,b为模糊系数,一般设置为2:
图 3 根据隶属度更新
算法步骤为:
- 确定聚类中心数目,初始化聚类中心
- 计算元素对各类的隶属度(图2),然后根据隶属度更新各个聚类中心(图3)
- 确定聚类停止条件或者设置迭代上限
代码如下
clc;
clearvars;
close all;
k=2;
count=0;
num=50;
for i=1:k
class(i)=struct('x',i*10,'y',10*i*10);
end
%%
%生成数据
for i=1:k
x=ones(num,1)*class(i).x+randn(num,1)*10;
y=ones(num,1)*class(i).y+randn(num,1)*10;
data(count+1:count+num,1)=x;
data(count+1:count+num,2)=y;
count=count+num;
% plot(x,y,'*');
end
%%
%生成不同分布的数据
% for i=1:k
% r=10*i;
% theta=0:0.01:2*pi;
% m=numel(theta);
% y=r*sin(theta)+randn(1,m)*1;
% x=r*cos(theta)+randn(1,m)*1;
% data(count+1:count+m,1)=x';
% data(count+1:count+m,2)=y';
% count=count+m;
% r=10*i;
% x=1:0.01:20;
% m=numel(x);
% y=r*x+randn(1,m)*5;
% data(count+1:count+m,1)=x';
% data(count+1:count+m,2)=y';
% count=count+m;
%
% plot(y,x,'.');
% hold on;
% end
%%
%fuzzy C cluster
%计算隶属度矩阵和聚类中心,使得目标函数最小
%算法步骤:初始化聚类中心,然后计算每一个样本对于每一类的隶属度,最终得到隶属度矩阵mu(i,j),i是类别,j是样本
%然后根据优化公式,更新聚类中心,最后计算目标函数,直到达到了迭代上限或者目标函数变化幅度变小
iter=1000;
b=2;%模糊度
mean=zeros(k,2);%初始化聚类中心
mu=zeros(k,count);%隶属度矩阵
figure,hold on;
for i=1:k
ind=floor(abs(rand()*count));
mean(i,1)=data(ind,1);
mean(i,2)=data(ind,2);
%plot(mean(i,1),mean(i,2),'rx','MarkerSize',15,'LineWidth',3);
end
while(iter)
iter=iter-1;
for j=1:count
dis=zeros(k,1);
add=0;
for i=1:k
dis(i,1)=1/((data(j,1)-mean(i,1))^2+(data(j,2)-mean(i,2))^2+0.01);%距离计算,加0.01是为了防0
add=add+dis(i,1);
end
for i=1:k
mu(i,j)=dis(i,1)/add;%计算隶属度矩阵
end
end
%更新聚类中心
for i=1:k
add=0;
means=zeros(1,2);
for j=1:count
add=add+mu(i,j)^b;
end
for j=1:count
means(1,:)=means(1,:)+mu(i,j)^b*data(j,:);
end
mean(i,:)=means(1,:)/add;
% plot(mean(i,1),mean(i,2),'rx','MarkerSize',15,'LineWidth',3);
% pause();
end
end
for i=1:k
plot(mean(i,1),mean(i,2),'rx','MarkerSize',15,'LineWidth',3);
% pause();
end
for j=1:count
dis=zeros(k,1);
add=0;
for i=1:k
dis(i,1)=1/((data(j,1)-mean(i,1))^2+(data(j,2)-mean(i,2))^2+0.01);
add=add+dis(i,1);
end
for i=1:k
mu(i,j)=dis(i,1)/add;
end
[m,ind]=max(mu(:,j));
if ind ==1
plot(data(j,1),data(j,2),'b.');
else
plot(data(j,1),data(j,2),'r.');
end
end
聚类效果如图:
图 4 结果图
3.GMM混合聚类
这个个人感觉就比较高大上了,它假定每一个样本是服从高斯分布的,它出现的概率由多个高斯分布决定:
图5 混合概率公式,其中alpha 其实就是下面的P(classi)
代表每一类高斯分布影响样本分布的概率
Pm表示的就是混合概率(就是加权啦)Pm(xi)代表的就是样本xi出现的概率,而和式里面的概率是在不同的高斯分布下样本xi出现的 概率,那么这和我们要求的给定样本xi分析其所属的类别c有什么关系呢?很简单,利用贝叶斯条件概率公式,我们可以反推出P(c|xi).
图5 混合概率公式
关于的计算,算法利用了EM(估计和极大似然)算法来求解最终可以得到更新公式(n为样本数):
在算法开始,先初始化c个标准高斯分布(,),然后每一个高斯分布出现的概率P(classi)=1/c;
图6 更新公式
高斯分布相较于之前提出的K-means 和Fuzzy-C来说,最核心的不同在于其假定的每一类概率分布的模式,前两种计算闵科夫斯基距离,那么从概率的角度来说,其是一个标准圆分布,圆心概率最高,这样针对下图这种样本分布来说,解决效果不是很好:
图7 k聚类分类结果
而高斯分布,可以通过调节协方差矩阵来改变其分布的形状,可以变成椭圆等各种形状,贴代码:
clc;
clearvars;
close all;
k=2;
count=0;
for i=1:k
% r=10*i;
% theta=0:0.01:2*pi;
% m=numel(theta);
% y=r*sin(theta)+randn(1,m)*1;
% x=r*cos(theta)+randn(1,m)*1;
% data(count+1:count+m,1)=x';
% data(count+1:count+m,2)=y';
% count=count+m;
r=10*i;
x=1:0.01:20;
m=numel(x);
y=r*x+randn(1,m)*5;
data(count+1:count+m,1)=x';
data(count+1:count+m,2)=y';
count=count+m;
%plot(y,x,'.');
%hold on;
end
figure,
plot(data(:,1),data(:,2),'.');
figure,
%%
%初始化k个高斯分布
alpha=double(ones(k,1)/k);
mean=zeros(k,2);
covar=zeros(2,2,k);
for i=1:k
ind=floor(abs(rand()*count));
mean(i,1)=data(ind,1);
mean(i,2)=data(ind,2);
covar(:,:,i)=[0.1 0;0 0.1]*1000;
end
plot(mean(:,1),mean(:,2),'rx','MarkerSize',15,'LineWidth',3);
%至此,我们可以根据上述初始化参数得到k个高斯分布,根据贝叶斯公式和高斯混合分布决定样本分布的公式计算出每一个样本属于
%某个分布的后验概率
iter=14;
while(iter)
iter=iter-1;
possibility_pre=zeros(count,k);
possibility=zeros(count,k);
possi=0;
for i=1:count
for j=1:k
sigma=covar(:,:,j);
possibility_pre(i,j)=mvnpdf(data(i,:),mean(j,:),sigma);
end
end
for i=1:count
add=0;
for j=1:k
add=add+alpha(j,1)*possibility_pre(i,j);
end
for j=1:k
possibility(i,j)=double(alpha(j,1)*possibility_pre(i,j)/add);
end
end
%更新各个高斯分布
for i=1:k
add=0;
add2=0;
add_sigma=zeros(2,2);
for j=1:count
add=add+possibility(j,i)*data(j,:);
add2=add2+possibility(j,i);
add_sigma=add_sigma+possibility(j,i)*(data(j,:)-mean(i,:))'*(data(j,:)-mean(i,:));
end
mean(i,:)=add/add2;
covar(:,:,i)=add_sigma/add2;
alpha(i,1)=add2/count;
end
end
for i=1:count
for j=1:k
sigma=covar(:,:,j);
possibility_pre(i,j)=mvnpdf(data(i,:),mean(j,:),sigma);
end
end
figure,hold on;
for i=1:count
add=0;
for j=1:k
add=add+alpha(j,1)*possibility_pre(i,j);
end
for j=1:k
possibility(i,j)=double(alpha(j,1)*possibility_pre(i,j)/add);
end
[m,ind]=max(possibility(i,:));
if ind==1
plot(data(i,1),data(i,2),'r.');
else
plot(data(i,1),data(i,2),'b.');
end
end
plot(mean(:,1),mean(:,2),'bx','MarkerSize',15,'LineWidth',3);
图8 GMM聚类分类结果