首页 > 学院 > 开发设计 > 正文

k-means聚类

2019-11-06 07:32:15
字体:
来源:转载
供稿:网友
KMeans.m%N是数据一共分多少类3%data是输入的不带分类标号的数据9x2%u是每一类的中心,随机产生3x2%re是返回的带分类标号的数据function [u re]=KMeans(data,N)       [m n]=size(data);   %m是数据个数,n是数据维数,比如现在有3类数据,9个点,都是二维的数据(1 1)(1 2)(2 1)、(9 9)(8 8)(7 7)、(9 1)(9 2)(8 2)    ma=zeros(1,n);        %每一维最大的数(9 9)    mi=zeros(1,n);        %每一维最小的数(1 1)    u=zeros(N,n);       %随机初始化,最终迭代到每一类的中心位置3x2    for i=1:n       ma(i)=max(data(:,i));    %每一维最大的数(9 9)       mi(i)=min(data(:,i));    %每一维最小的数(1 1)       for j=1:N            u(j,i)=ma(i)+(mi(i)-ma(i))*rand();  %随机初始化,不过还是在每一维[min max]中初始化好些,就是一个长方形框       end          end       while 1      %1是判断表达式 1永远为真 即永远循环 但循环必须是有限 循环体中必须存在终止循环语句break        PRe_u=u;            %上一次求得的中心位置 3x2,后面的u会变化(公式2),这里先用一个新变量保存下        for i=1:N           %第一类到第三类            tmp{i}=[];      % 公式一中的x(i)-uj,为公式一实现做准备!!!!!。这个是单元数组,分配三个cell单元            for j=1:m    %1到9个数据                tmp{i}=[tmp{i};data(j,:)-u(i,:)];  %9个数据都和第一个、第二个、第三个中心位置相减,                                       %如果没有[tmp{i};得到的单元数组是1x2的,因为被覆盖掉了,只有第九个数据和类别中心相减的结果                                       %这个就是有点像累加器,循环得到下一个相减的坐标就累加到原来单元的下面,最后每个类别得到9x2的矩阵 end        end                quan=zeros(m,N);     % 9x3        for i=1:m        %公式一的实现   i表示1到9的数据个数            c=[];  %循环一次后c又被清空            for j=1:N   %类别一到类别三,tmp有3个单元                c=[c norm(tmp{j}(i,:))];   %norm是范数,这里2范数,是距离,向量的模长,坐标差模长就是距离,[c ]还是累加器的功能,(i,:)不要覆盖            end   %第一个循环结束,第一个数据离3个坐标中心的距离形成3x1数组            [junk index]=min(c); %junk是c的最小值,index表示最小值出现的位置,也就是应该分到第几类            quan(i,index)=norm(tmp{index}(i,:)); %quan的i行index列,赋值为距离                  end          %quan被填满了,每行有2个位置是0 for i=1:N            %公式二的实现,类别一到类别三           for j=1:n  %第一维到第二维,,u是3行2列                u(i,j)=sum(quan(:,i).*data(:,j))/sum(quan(:,i));  %其实应该是按照距离加权求新质心的坐标           end                   end                if norm(pre_u-u)<0.1  %不断迭代直到位置不再变化            break;        end    end        re=[];     %re是返回的带分类标号的数据    for i=1:m           tmp=[];        for j=1:N            tmp=[tmp norm(data(i,:)-u(j,:))];        end        [junk index]=min(tmp);  %说距离是垃圾junk,没用的不关心,只关心是距离拿一个分类中心更近        re=[re;data(i,:) index];  % 每一行是原始数据和分类标号    end    end

以上是算法

以下是实例

数据是三维的

clear all;close all;clc;%第一类数据mu1=[0 0 0];  %均值S1=[0.3 0 0;0 0.35 0;0 0 0.3];  %协方差 3x2data1=mvnrnd(mu1,S1,100);   %产生高斯分布数据%%第二类数据mu2=[1.25 1.25 1.25];S2=[0.3 0 0;0 0.35 0;0 0 0.3];data2=mvnrnd(mu2,S2,100);%第三个类数据mu3=[-1.25 1.25 -1.25];S3=[0.3 0 0;0 0.35 0;0 0 0.3];data3=mvnrnd(mu3,S3,100);%显示数据plot3(data1(:,1),data1(:,2),data1(:,3),'+');  %plot3是三维的图,所以你后面参数必须有三个,data1的三维拆开来写hold on;plot3(data2(:,1),data2(:,2),data2(:,3),'r+');plot3(data3(:,1),data3(:,2),data3(:,3),'g+');grid on;%三类数据合成一个不带标号的数据类data=[data1;data2;data3];   %这里的data是不带标号的%k-means聚类[u re]=KMeans(data,3);  %最后产生带标号的数据,标号在所有数据的最后[m n]=size(re); %最后显示聚类后的数据
%u是每一类的中心,%re是返回的带分类标号的数据figure;hold on;for i=1:m if re(i,4)==1 %m个数据里面,每个数据xyz三个轴参数,第四个是分类标号 plot3(re(i,1),re(i,2),re(i,3),'ro'); elseif re(i,4)==2 plot3(re(i,1),re(i,2),re(i,3),'go'); else plot3(re(i,1),re(i,2),re(i,3),'bo'); endendgrid on;


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表