matlab实现kmeans聚类算法

kmeans聚类算法是一种简单实用的聚类算法,matlab自带函数kmeans可直接对数据进行kmeans聚类。为了方便更好地掌握kmeans聚类算法,今天我们自己来实现一个弱化的版本mykmeans。

mykmeans输入包含三项,分别为聚类所使用的数据data,data每一行代表一个样本,每一列代表一个特征;聚类中心数量numclass;第三项为所使用的距离的定义,默认情况下为欧式距离。

function [cluster,clusterhistory]=mykmeans(data,numclass,varargin)
% kmeans聚类。
% 聚类过程动画显示
% INPUTS:
% data:每一行代表一个样本,每一列代表一个特征
% numclass:聚类中心的数量
% varargin{1}: 距离定义。支持euclidean(默认)、hamming
% OUTPUT:
% cluster: numsample行的列向量,代表每个样本的分类归属
% clusterhistory{i}.cluster第i次迭代的聚类
% clusterhistory{i}.core第i次迭代的聚类中心
%
% 公众号【数学建模公会】,HCLO4,20190902

if nargin==2
    method='euclidean';
else
    method=varargin{1};
end
% 初始化聚类中心坐标,在数据点中随机选择numclass个点作为初始聚类中心。
numsample=size(data,1);
temp=randperm(numsample);
core=data(temp(1:numclass),:);
dis=caldis(data,core,method); %存储每个样本到当前聚类中心的距离


% 执行迭代过程
maxIter=20; % 最大迭代次数
numiter=1;
clusterhistory=cell(1,maxIter);
while 1
    
    newcore=zeros(size(core));
    % 迭代聚类中心
    [~,ind]=min(dis,[],2); %计算每个sample归属于哪个聚类中心,如果某个聚类中心没有一个点?
    for i=1:numclass
        newcore(i,:)=mean(dis(ind==i,:));
    end
    clusterhistory{numiter}.cluster=ind;
    clusterhistory{numiter}.core=core;
    
    if all(newcore(:)==core(:))||numiter>=maxIter  % 迭代终止条件,聚类中心不再改变
        cluster=ind;
        break
    end
    
    core=newcore;
    dis=caldis(data,core,method); 
    
    numiter=numiter+1;
    
end
    

clusterhistory=clusterhistory(1:numiter);


end % mykmeans



function dis=caldis(data,core,method)
%计算每个样本到当前聚类中心的距离
numsample=size(data,1);
numclass=size(core,1);
dis=zeros(numsample,numclass);
switch method
    case 'euclidean'
        for i=1:numclass
            dis(:,i)=sqrt(sum((data-repmat(core(i,:),numsample,1)).^2,2));
        end
    case 'hamming'
        for i=1:numclass
            dis(:,i)=mean(data~=repmat(core(i,:),numsample,1),2);
        end
end

下面一段代码用于测试mykmeans和kmeans的运行结果。生成两组服从二维高斯分布的数据,作为两个数据类别,分别使用mykmeans和matlab自带的kmeans函数进行聚类分析。

% 测试mykmeans函数
% 公众号【数学建模公会】,HCLO4,20190902

% 生成模拟数据,平面上的两组点,均服从二维高斯分布
mu1=[2,8];
sigma1=[2,2];
mu2=[8,2];
sigma2=[3,3];

numsample1=100;
numsample2=200;
data1=zeros(numsample1,2);
data1(:,1)=normrnd(mu1(1),sigma1(1),numsample1,1);
data1(:,2)=normrnd(mu1(2),sigma1(2),numsample1,1);

data2=zeros(numsample2,2);
data2(:,1)=normrnd(mu2(1),sigma2(1),numsample2,1);
data2(:,2)=normrnd(mu2(2),sigma2(2),numsample2,1);

data=[data1;data2];

tic,
[cluster1,clusterhistory]=mykmeans(data,2);
toc
M=getFrame_Kmeans(data,clusterhistory); % 生成聚类动图

tic,
cluster2=kmeans(data,2);
toc

下面的函数实现mykmeans聚类过程的可视化,仅针对二维数据和三维数据类型。

function M=getFrame_Kmeans(data,clusterhistory)
% kmeans聚类过程可视化程序。只能对二维和三维数据可视化!
%
% INPUTS: 
% data: 聚类用的数据,每行代表一个样本,每列代表一个特征
% clusterhistory: mykmeans函数输出的聚类过程数据
%
% OUTPUT:
% kmeans聚类过程的动画。

dimension=size(data,2);
if dimension>3 % 若三维以上,只能通过pca降维处理
    error('无法实现高于三维的数据的聚类可视化')
end

colorset=cell(1,1000);
colorset(1:8)={'r','g','b','k','c','m','y','k'};
for i=9:1000 %如果聚类中心数量大于8,就使用随机的颜色。
    colorset{i}=rand(1,3);
end

numcore=length(unique(clusterhistory{1}.cluster));
numiter=length(clusterhistory);

for k=1:numiter
    figure
    hold on
    switch dimension
        case 2
            for i=1:numcore
                ind=clusterhistory{k}.cluster==i;
                scatter(data(ind,1),data(ind,2),6,colorset{i})
                core=clusterhistory{k}.core;
                plot(core(i,1),core(i,2),[colorset{i},'.'],'MarkerSize',20)
            end
        case 3
            for i=1:numcore
                ind=clusterhistory{k}.cluster==i;
                scatter3(data(ind,1),data(ind,2),data(ind,3),6,colorset{i})
                core=clusterhistory{k}.core;
                plot3(core(i,1),core(i,2),core(i,3),colorset{i},'MarkerSize',6)
            end
    end
    
    M(k)=getframe(gcf);
    frame = getframe(gcf); 
    im = frame2im(frame);     %将影片动画转换为编址图像,因为图像必须是index索引图像
    imshow(im);
    [I,map] = rgb2ind(im,20); %将真彩色图像转化为索引图像
    if k==1
        imwrite(I,map,'kmeans.gif','gif','Loopcount',inf,'DelayTime',0.3);     %Loopcount只是在i==1的时候才有用
    else
        imwrite(I,map,'kmeans.gif','gif','WriteMode','append','DelayTime',1);%DelayTime:帧与帧之间的时间间隔
    end
    
    
    close(gcf);
    
end
  • 6
    点赞
  • 85
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值