K-means聚类算法和模糊C-means聚类算法

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

K-means聚类算法和模糊C-means聚类算法

1.K-means聚类算法

K-means算法是硬聚类算法,是典型的基于原型的目标函数聚类方法的代表,它是数据点到原型的某种距离作为优化的目标函数,利用函数求极值的方法得到迭代运算的调整规则。K-means算法以欧式距离作为相似度测度,它是求对应某一初始聚类中心向量V最优分类,使得评价指标J最小。算法采用误差平方和准则函数作为聚类准则函数。

K-Means聚类算法的优点主要集中在:

1.算法快速、简单;

2.对大数据集有较高的效率并且是可伸缩性的;

3.时间复杂度近于线性,而且适合挖掘大规模数据集。K-Means聚类算法的时间复杂度是O(nkt) ,其中n代表数据集中对象的数量,t代表着算法迭代的次数,k代表着簇的数目。

K-Means聚类算法的缺点:

① 在 K-means 算法中 K 是事先给定的,这个 K 值的选定是非常难以估计的。很多时候,事先并不知道给定的数据集应该分成多少个类别才最合适。这也是 K-means 算法的一个不足。有的算法是通过类的自动合并和分裂,得到较为合理的类型数目 K,例如 ISODATA 算法。关于 K-means 算法中聚类数目K 值的确定在文献中,是根据方差分析理论,应用混合 F统计量来确定最佳分类数,并应用了模糊划分熵来验证最佳分类数的正确性。在文献中,使用了一种结合全协方差矩阵的 RPCL 算法,并逐步删除那些只包含少量训练数据的类。而文献中使用的是一种称为次胜者受罚的竞争学习规则,来自动决定类的适当数目。它的思想是:对每个输入而言,不仅竞争获胜单元的权值被修正以适应输入值,而且对次胜单元采用惩罚的方法使之远离输入值。

② 在 K-means 算法中,首先需要根据初始聚类中心来确定一个初始划分,然后对初始划分进行优化。这个初始聚类中心的选择对聚类结果有较大的影响,一旦初始值选择的不好,可能无法得到有效的聚类结果,这也成为 K-means算法的一个主要问题。对于该问题的解决,许多算法采用 遗传算法(GA),例如文献 中采用遗传算法(GA)进行初始化,以内部聚类准则作为评价指标。
③ 从 K-means 算法框架可以看出,该算法需要不断地进行样本分类调整,不断地计算调整后的新的聚类中心,因此当数据量非常大时,算法的时间开销是非常大的。所以需要对算法的时间复杂度进行分析、改进,提高算法应用范围。在文献中从该算法的时间复杂度进行分析考虑,通过一定的相似性准则来去掉聚类中心的侯选集。而在文献中,使用的 K-means 算法是对样本数据进行聚类,无论是初始点的选择还是一次迭代完成时对数据的调整,都是建立在随机选取的样本数据的基础之上,这样可以提高算法的收敛速度。
下面给出例子,有34个地点的经纬度如下:

13.5667000000000	9.63330000000000
11.7833000000000	11.4833000000000
14.0167000000000	10.1833000000000
12.4000000000000	11.0500000000000
11.1000000000000	10.7167000000000
10.1167000000000	9.16670000000000
8.81670000000000	7.73330000000000
10.1333000000000	8.53330000000000
9.46670000000000	8.53330000000000
9.25000000000000	7.55000000000000
9.88330000000000	10.6333000000000
9.16670000000000	11.4167000000000
10.5667000000000	8.26670000000000
11.1833000000000	7.86670000000000
10.8833000000000	8.75000000000000
12.1500000000000	9.23330000000000
12.9167000000000	9.11670000000000
12.7833000000000	8.76670000000000
11.7833000000000	8.73330000000000
11.7333000000000	7.96670000000000
12.5000000000000	7.51670000000000
12.4167000000000	8.15000000000000
11.6833000000000	7.35000000000000
6.76830000000000	7.03210000000000
13.2167000000000	8.46670000000000
10.8167000000000	6.75000000000000
9.66670000000000	6.91670000000000
9.78330000000000	6.20000000000000
11.0167000000000	7.10000000000000
10.0667000000000	7.70000000000000
10.2167000000000	6.50000000000000
10.5667000000000	6.50000000000000
8.76670000000000	6.81670000000000
9.36670000000000	5.86670000000000
matlab程序如下:

% 簇心数目k
K = 8;

data=jw; % 直接存储到data变量中

x = data(:,1);
y = data(:,2);

% 绘制数据,2维散点图
% x,y: 要绘制的数据点  20:散点大小相同,均为20  'blue':散点颜色为蓝色
s = scatter(x, y, 20, 'blue');
title('原始数据:蓝圈;初始簇心:红点');

% 初始化簇心
sample_num = size(data, 1);       % 样本数量
sample_dimension = size(data, 2); % 每个样本特征维度

% 暂且手动指定簇心初始位置
% clusters = zeros(K, sample_dimension);
% clusters(1,:) = [-3,1];
% clusters(2,:) = [2,4];
% clusters(3,:) = [-1,-0.5];
% clusters(4,:) = [2,-3];
% 簇心赋初值:计算所有数据的均值,并将一些小随机向量加到均值上
clusters = zeros(K, sample_dimension);
minVal = min(data); % 各维度计算最小值
maxVal = max(data); % 各维度计算最大值
for i=1:K
    clusters(i, :) = minVal + (maxVal - minVal) * rand();
end 


hold on; % 在上次绘图(散点图)基础上,准备下次绘图
% 绘制初始簇心
scatter(clusters(:,1), clusters(:,2), 'red', 'filled'); % 实心圆点,表示簇心初始位置

c = zeros(sample_num, 1); % 每个样本所属簇的编号

PRECISION = 0.001;


iter = 100; % 假定最多迭代100次
% Stochastic Gradient Descendant 随机梯度下降(SGD)的K-means,也就是Competitive Learning版本
basic_eta = 1;  % learning rate
for i=1:iter
    pre_acc_err = 0;  % 上一次迭代中,累计误差
    acc_err = 0;  % 累计误差
    for j=1:sample_num
        x_j = data(j, :);     % 取得第j个样本数据,这里体现了stochastic性质

        % 所有簇心和x计算距离,找到最近的一个(比较簇心到x的模长)
        gg = repmat(x_j, K, 1);
        gg = gg - clusters;
        tt = arrayfun(@(n) norm(gg(n,:)), (1:K)');
        [minVal, minIdx] = min(tt);

        % 更新簇心:把最近的簇心(winner)向数据x拉动。 eta为学习率.
        eta = basic_eta/i;
        delta = eta*(x_j-clusters(minIdx,:));
        clusters(minIdx,:) = clusters(minIdx,:) + delta;
        acc_err = acc_err + norm(delta);
        c(j)=minIdx;
    end
    
    if(rem(i,10) ~= 0)
        continue
    end
    figure;
    f = scatter(x, y, 20, 'blue');
    hold on;
    scatter(clusters(:,1), clusters(:,2), 'filled'); % 实心圆点,表示簇心初始位置
    title(['第', num2str(i), '次迭代']);
    if (abs(acc_err-pre_acc_err) < PRECISION)
        disp(['收敛于第', num2str(i), '次迭代']);
        break;
    end
    
    disp(['累计误差:', num2str(abs(acc_err-pre_acc_err))]);
    pre_acc_err = acc_err;
end


disp('done');

得到前90次迭代的结果如下:






得到的第100次迭代结果为:


用线条将聚类中心与成员连接起来


1.模糊C-means聚类算法

模糊c-均值聚类算法 fuzzy c-means algorithm (FCMA)或称( FCM)。在众多模糊聚类算法中,模糊C-均值( FCM) 算法应用最广泛且较成功,它通过优化目标函数得到每个样本点对所有类中心的隶属度,从而决定样本点的类属以达到自动对样本数据进行分类的目的。

算法原理


用法: 
1. [center,U,obj_fcn] = FCM(Data,N_cluster,options); 
2. [center,U,obj_fcn] = FCM(Data,N_cluster);

输入变量 
data ---- n*m矩阵,表示n个样本,每个样本具有m维特征值 
cluster_n ---- 标量,表示聚合中心数目,即类别数 
options ---- 4*1列向量,其中 
options(1): 隶属度矩阵U的指数,>1(缺省值: 2.0) 
options(2): 最大迭代次数(缺省值: 100) 
options(3): 隶属度最小变化量,迭代终止条件(缺省值: 1e-5) 
options(4): 每次迭代是否输出信息标志(缺省值: 0) 

输出变量 
center ---- 聚类中心 
U ---- 隶属度矩阵 
obj_fcn ---- 目标函数值 

编写C-means函数为:

function[center,U,obj_fun]=FCMCluster(data,n,options)
%采用模糊C均值将数据集data分为n类
%用法
% 1 [center,U,obj_fcn]=FCMCluster(data,n,options);
% 2 [center,U,obj_fcn]=FCMCluster(data,n);

%输入 
% data    n*m矩阵,n个样本数,每个样本的维度为m
% n       类别数
% options 4*1 矩阵
%   options(1):隶属度矩阵U的加权指数
%   options(2):最大迭代次数
%   options(3):隶属度最小变化量,迭代终止条件
%   options(4):每次迭代是否输出信息标志

%输出
% center    聚类中心
% U         隶属度矩阵
% obj_fun   目标函数值


if nargin~=2 && nargin~=3
    error('Too many or too few input arguments');
end 

data_n=size(data,1);
in_n=size(data,2);

%默认参数
default_options=[2;100;1e-5;1];

%参数配置
  %如果只输入前两个参数,选用默认的参数;如果参数个数小于4,其他选用默认参数
  if nargin==2
      options=default_options;
  else
       if length(options)<4
           tmp=default_options;
           tmp(1:length(options))=options;
           options=tmp;
       end 
       nan_index=find(isnan(options)==1);
       options(nan_index)=default_options(nan_index);

       if options(1)<=1
           error('The exponent should be greater than 1!');
       end 
  end 

  %将options 中的分量分别赋值给四个变量
  expo=options(1);
  max_iter=options(2);
  min_impro=options(3);
  display=options(4);

  obj_fun=zeros(max_iter,1);

  %初始化模糊分配矩阵
  U=initfcm(n,data_n);


  %主程序
   for i=1:max_iter
       [U,center,obj_fun(i)]=stepfcm(data,U,n,expo);
       if display
           fprintf('FCM:Iteration count=%d,obj_fun=%f\n',i,obj_fun(i));
       end
       %终止条件判别
       if i>1
           if abs(obj_fun(i)-obj_fun(i-1))<min_impro
               break;
           end 
       end 
   end
   iter_n=i;
   obj_fun(iter_n+1:max_iter)=[];
%   

end
%%子函数 模糊矩阵初始化
    function U= initfcm(n,data_n)
        U=rand(n,data_n);
        col_sum=sum(U);
        U=U./col_sum(ones(n,1),:);
    end


%%子函数 逐步聚类
        function [U_new,center,obj_fun]=stepfcm(data,U,n,expo)
            mf=U.^expo;
            center=mf*data./((ones(size(data,2),1)*sum(mf'))');
            dist=distfcm(center,data);
            obj_fun=sum(sum((dist.^2).*mf));
            tmp=dist.^(-2/(expo-1));
            U_new=tmp./(ones(n,1)*sum(tmp));
        end


%%子函数 计算距离
            function out=distfcm(center,data)
                out=zeros(size(center,1),size(data,1));
                for k=1:size(center,1)
                    out(k,:)=sqrt(sum(((data-ones(size(data,1),1)*center(k,:)).^2)',1));


                end 
            end
脚本函数为:

data=jw;
options = [2;100;1e-5;1]; 
[center,U,obj_fcn] = FCMCluster(data,8,options); 
plot(data(:,1),data(:,2),'o'); 
hold on; 
index1=find(U(1,:)==max(U));%找出划分为第一类的数据索引 
index2=find(U(2,:)==max(U));%找出划分为第二类的数据索引 
index3=find(U(3,:)==max(U));%找出划分为第三类的数据索引 
index4=find(U(4,:)==max(U));%找出划分为第四类的数据索引 
index5=find(U(5,:)==max(U));%找出划分为第五类的数据索引 
index6=find(U(6,:)==max(U));%找出划分为第六类的数据索引 
index7=find(U(7,:)==max(U));%找出划分为第七类的数据索引 
index8=find(U(8,:)==max(U));%找出划分为第八类的数据索引 
plot(data(index1,1),data(index1,2),'g*'); 
hold on; 
plot(data(index2,1),data(index2,2),'r*'); 
hold on; 
plot(data(index3,1),data(index3,2),'b*'); 
hold on;
plot(data(index4,1),data(index4,2),'c*'); 
hold on;
plot(data(index5,1),data(index5,2),'m*'); 
hold on;
plot(data(index6,1),data(index6,2),'y*'); 
hold on;
plot(data(index7,1),data(index7,2),'k*'); 
hold on;
plot(data(index8,1),data(index8,2),'w*'); 
hold on;
plot([center([1:8],1)],[center([1:8],2)],'p','color','r');
grid on
得到的结果如下:


通过结果来看,C-means聚类的结果要好些,最左边的地点并没有单独聚类一个类,在实际情况中运用更加广泛。

猜你喜欢

转载自blog.csdn.net/wzl1997/article/details/79264560