用matlab实现k-means聚类

本文介绍了如何在MATLAB中实现k-means聚类算法,详细讲解了聚类概念、k-means算法步骤,并通过学生成绩数据进行实践,分析了不同程序的运行结果和可能的误判情况,探讨了k-means在小样本数据时的局限性。

用matlab实现k-means聚类

本文是大三下学期课程《数据分析方法》中的一些简单实现,部分内容摘自《大数据分析:方法和应用》一书。本文仅作为学习总结用,不作商用

本文思路:
聚类的概念
k-means算法的思路和步骤
matlab的实现
运行结果分析


一、聚类的概念
聚类是数据挖掘比较常见的方法,也相对比较简单。
聚类分析的目的在于把分类对象按一定的规则分成若干类,这些类没有预先给定,而是根据数据的特征而确定的,对于类的数目以及类的结构不用作任何假定。聚类和分类是不一样的,聚类的类似并没有事先确定,聚类属于搜索簇的无监督学习过程。而分类,就是根据文本的特征或属性,将待分类点划分到已有的类别中。分类属于有监督学习
聚类分析根据分类对象的不同还分为Q型聚类分析R型聚类分析Q型聚类分析是指对样品的聚类,R型聚类分析是指对变量的聚类。


二、k-means算法的思路和步骤
k-means算法是一种应用范围比较广的聚类方法。其思想在于在给定的聚类数k时,通过最小化组内误差平方和来得到每一个样本点的分类。


步骤:

  • 1.先在所有的样本(n个)中随机选择k个样本点作为初始的聚类中心;
  • 2.计算k个聚类中心到剩下的n-k个样本点的距离,根据剩下的n-k个样与聚类中心的距离,分别将它们分到与其最近的中心的类中;
  • 3.计算每个新类的聚类中心;
  • 4.重复2、3,直到所有样本点的分类不再改变或者类中心不再改变。

三、matlab的实现
由于我使用的是学生成绩作为训练集,学生成绩分为两类(及格和不及格),因此在训练的时候,k=2,这里的k是通用的,可以是其他值。

使用工具:matlab2015b
训练集:88个学生成绩,每个样本维数为2,平时成绩和期末成绩,其中及格人数为51,不及格人数为37。

程序一
这个程序是刚开始做的,当时想着找一个“容器”来储存类别,后来发现元胞数组能实现这种功能(储存“一堆”行数不同的矩阵),元胞数组其实有点像R语言中的“dataframe”,其中的元素可以多种多样

function [Class,temp,new_C,iter] =k_means(train,k)
%train是训练的样本,k是自行设定的聚类数
%这个程序是针对k的聚类,元胞数组,添加了IDX
[n,dim]=size(train);
train=[train zeros(n,1)];
r=randsample(n,k);%r是从n中随机不重复抽出k个整数
C=train(r,1:end-1);delta=ones(1,1);
tao=0.001;iter=0;
while delta>=tao
    D=[];train(:,end)=0;
    %计算样本到聚类中心的距离
    for j=1:k
        D=[D,sqrt(sum((repmat(C(j,:),n,1)-train(:,1:end-1)).^2,2))];
    end
    Class=cell(k,1);%将样本归类  
   for i=1:n
    [~,d]=min(D(i,:));
    Class{d,1}(i,:)=train(i,:);
    train(i,dim+1)=d;
   end
   new_C=zeros(k,dim);
   %计算新的聚类中心
   for j=1:k
       M=cell2mat(Class(j,1)); M(all(M==0,2),:)=[]; Class{j,1}=M;
       new_C(j,:)=mean(Class{j,1}(:,1:end-1));
   end
    delta=norm(new_C-C);%计算上一次的聚类中心与新的聚类中心的距离
    C=new_C;
    iter=iter+1;
    temp=train;
end
end

运行结果

>> [Class,temp,new_C,iter] =k_means(train,k)

Class = 

    [36x3 double]
    [52x3 double]


temp =

    60     0     2
    50    53     2
    70    76     1
    60    61     2
    90    59     1
    60    25     2
    80    78     1
    90    59     1
    90    80     1
    60    76     2
    70    60     2
    60    53     2
    80    53     1
    90    61     1
    95    65     1
   100    41     1
    90    68     1
    60    64     2
   100    69     1
    80    38     2
    90    76     1
    60    61     2
   100    73     1
   100    71     1
    60    48     2
    60    61     2
    60    58     2
   100    53     1
    80    43     2
   100    69     1
   100    59     1
    60    73     2
    90    32     2
   100    76     1
   100    83     1
    75    38     2
    80    59     1
    60    60     2
    50    73     2
    80    40     2
    70    43     2
    70    46     2
    80    73     1
    70    71     2
   100    71     1
   100    53     1
    80    67     1
   100    65     1
    50    33     2
    50    53     2
    50    46     2
    90    48     1
    60    25     2
   100    78     1
    60    25     2
    70    62     2
    90    59     1
    60    51     2
    60    68     2
    60    70     2
   100    40     1
   100    50     1
    60    53     2
    60    56     2
    60    51     2
    50    31     2
    60    11     2
    60    58     2
    70    20     2
    70    43     2
    60    38     2
    95    63     1
    90    48     1
    70    56     2
    60    48     2
    60    36     2
    80    63     1
   100    66     1
    60    38     2
    60    63     2
   100    63     1
    70    69     2
    60    25     2
    60    50     2
    90    64     1
    70    59     2
    70    68     2
    60    35     2


new_C =

   92.7778   63.8611
   62.9808   48.4231


iter =

     5

程序二
这个程序比前面的改进了,没有用元胞数组来储存类,而是在每一次归类的时候在训练集train后面直接添加索引。

function [temp,new_C,iter,k1,k2] =k_means2(train,k)
%改进版,不用元胞数组
[n,dim]=size(train);
train=[train zeros(n,1)];
r=randsample(n,k);%r是从n中随机不重复抽出k个整数
C=train(r,1:end-1);delta=ones(1,1);
tao=0.001;iter=0;
while delta>tao
     D=[];train(:,end)=0;%在训练样本的最后添加一列,用来记录类号
    for j=1:k
        D=[D,sqrt(sum((repmat(C(j,:),n,1)-train(:,1:end-1)).^2,2))];
    end
    for i=1:n
    [~,d]=min(D(i,:));
    train(i,dim+1)=d;
    end
    new_C=zeros(k,dim);
    for j=1:k
        new_C(j,:)=mean(train(train(:,end)==j,1:dim));
    end
    delta=norm(new_C-C);%计算上一次的聚类中心与新的聚类中心的聚离
    C=new_C;
    iter=iter+1;
    temp=train;%temp最后输出的是带有类号的训练集
end
plot(temp(temp(:,end)==1,1),temp(temp(:,end)==1,2),'b*');
hold on;
plot(temp(temp(:,end)==2,1),temp(temp(:,end)==2,2),'r*');
k1=size(temp(temp(:,end)==1,:),1);%统计1类的数目
k2=size(temp(temp(:,end)==2,:),1);%统计2类的数目
end

运行结果

>> [temp,new_C,iter,k1,k2] =k_means2(train,k)

temp =

    60     0     2
    50    53     2
    70    76     1
    60    61     2
    90    59     1
    60    25     2
    80    78     1
    90    59     1
    90    80     1
    60    76     2
    70    60     2
    60    53     2
    80    53     1
    90    61     1
    95    65     1
   100    41     1
    90    68     1
    60    64     2
   100    69     1
    80    38     2
    90    76     1
    60    61     2
   100    73     1
   100    71     1
    60    48     2
    60    61     2
    60    58     2
   100    53     1
    80    43     2
   100    69     1
   100    59     1
    60    73     2
    90    32     1
   100    76     1
   100    83     1
    75    38     2
    80    59     1
    60    60     2
    50    73     2
    80    40     2
    70    43     2
    70    46     2
    80    73     1
    70    71     2
   100    71     1
   100    53     1
    80    67     1
   100    65     1
    50    33     2
    50    53     2
    50    46     2
    90    48     1
    60    25     2
   100    78     1
    60    25     2
    70    62     2
    90    59     1
    60    51     2
    60    68     2
    60    70     2
   100    40     1
   100    50     1
    60    53     2
    60    56     2
    60    51     2
    50    31     2
    60    11     2
    60    58     2
    70    20     2
    70    43     2
    60    38     2
    95    63     1
    90    48     1
    70    56     2
    60    48     2
    60    36     2
    80    63     1
   100    66     1
    60    38     2
    60    63     2
   100    63     1
    70    69     2
    60    25     2
    60    50     2
    90    64     1
    70    59     2
    70    68     2
    60    35     2


new_C =

   92.7027   63.0000
   62.4510   48.7451


iter =

     4


k1 =

    37

聚类效果

结果分析:

  • 程序一和程序二的运行时间和聚类效果别无二致,思路也大致相同。但是程序二更加好理解,因为不用元胞数组。
  • 实现的k-means聚出来的类数和实际情况有时会有差别(最多差别3个),也存在误判的情况,误判主要集中的边界处。
  • 聚类分析更加适合于大样本数据,样本数据少时,聚类效果不会很好。

k-means聚类存在的问题

  • 容易受到初始聚类中心选择的影响,在分类数据上分辨力不强,不适用于非凸问题,容易受到异常数据的影响。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值