这是我的第一篇博客;
K-Means算法过程,略;
这是一次课程的任务2333,是利用所学K-means聚类分析方法,对iris数据集进行聚类分析,并利用已知的样本类别标
签进行聚类分析评价;
我的K均值算法以iris.data为例(附在文末);
数据集:Iris数据集
(http://archive.ics.uci.edu/ml/datasets/Iris)
数据描述:Iris数据集包含150个鸢尾花模式样本,其中 每个模式样本采用5维的特征描述
X = (x1,x2,x3,x4,w);
x1: 萼片长度(厘米)
x2: 萼片宽度(厘米)
x3: 花瓣长度(厘米)
x4:花瓣宽度(厘米)
w(类别属性 ): 山鸢尾 (Iris setosa),变色鸢尾(Iris versicolor)和维吉尼亚鸢尾(Iris virginica)
先贴上我的函数结构:
函数结构 —— FindCluster(~) 聚类算法主函数 | MyKmeans —— MyPlot2(~),MyPlot3(~) 画图 | —— Accuracy(~) 聚类精度评价
MyKmean.m,程序运行的主函数
% 作者 : YG1501 LQY % 日期 : 2018.01.13 星期六 % 函数功能 : 实现对iris.data数据集的分类,并根据分类结果进行精度评价 clear;clc;close all; %手动选取文件,选用iris.data [filename,fpath] = uigetfile(... {... '*.m;*.txt;*.data',... 'Data(*.m;*.txt;*.data)';... '*.*','All Files(*.*)'... },'Select data'); [X1,X2,X3,X4,X5] = ... textread(filename,'%f%f%f%f%s','delimiter',','); %Get data X = [X1 X2 X3 X4]; %目前貌似还没什么用 [m,n] = size(X); DataLabel = zeros(m,1); for i = 1:size(X5,1) if (strcmp(X5(i),'Iris-setosa')) DataLabel(i) = 1 ; elseif(strcmp(X5(i),'Iris-versicolor')) DataLabel(i) = 2 ; else DataLabel(i) = 3 ; end end %二维结果 [MyCenter1,ClusterLabel12] = FindCluster([X1 X2],3,DataLabel); [MyCenter2,ClusterLabel13] = FindCluster([X1 X3],3,DataLabel); [MyCenter3,ClusterLabel14] = FindCluster([X1 X4],3,DataLabel); [MyCenter4,ClusterLabel23] = FindCluster([X2 X3],3,DataLabel); [MyCenter5,ClusterLabel24] = FindCluster([X2 X4],3,DataLabel); [MyCenter6,ClusterLabel34] = FindCluster([X3 X4],3,DataLabel); hold on; figure(1),title('2D'); subplot(231) MyPlot2(X1,X2,DataLabel,MyCenter1),xlabel('X1'),ylabel('X2') subplot(232) MyPlot2(X1,X3,DataLabel,MyCenter2),xlabel('X1'),ylabel('X3') subplot(233) MyPlot2(X1,X4,DataLabel,MyCenter3),xlabel('X1'),ylabel('X4') subplot(234) MyPlot2(X2,X3,DataLabel,MyCenter4),xlabel('X2'),ylabel('X3') subplot(235) MyPlot2(X2,X4,DataLabel,MyCenter5),xlabel('X2'),ylabel('X4') subplot(236) MyPlot2(X3,X4,DataLabel,MyCenter6),xlabel('X3'),ylabel('X4') %三维结果 % [MyCenter7,ClusterLabel123] = FindCluster([X1,X2,X3],3,DataLabel); % [MyCenter8,ClusterLabel124] = FindCluster([X1,X2,X4],3,DataLabel); % [MyCenter9,ClusterLabel134] = FindCluster([X1,X3,X4],3,DataLabel); % [MyCenter10,ClusterLabel234] = FindCluster([X2,X3,X4],3,DataLabel); % hold on; % figure(2),title('3D'); % subplot(221) % MyPlot3(X1,X2,X3,DataLabel,MyCenter7) % xlabel('X1'),ylabel('X2'),zlabel('X3'); % subplot(222) % MyPlot3(X1,X2,X4,DataLabel,MyCenter8) % xlabel('X1'),ylabel('X2'),zlabel('X4'); % subplot(223) % MyPlot3(X1,X3,X4,DataLabel,MyCenter9) % xlabel('X1'),ylabel('X3'),zlabel('X4'); % subplot(224) % MyPlot3(X2,X3,X4,DataLabel,MyCenter10) % xlabel('X2'),ylabel('X3'),zlabel('X4'); %聚类精度评价 %二维结果 ClusterLabel = [ClusterLabel12,ClusterLabel13,ClusterLabel14... ClusterLabel23,ClusterLabel24,ClusterLabel34] ClusterAccuracy = Accuracy(DataLabel,ClusterLabel) % 输出每种分类的精度 %三维结果 %略这里要说明的一点是,我的函数的运行效率比较低,建议运行时只单独进行二维的分类或三维的分类。。运算量比较多,在二维空间上大概需要5秒钟才能出结果。。。
FindCluster.m
%函数功能 : 输入数据集、聚类中心个数与样本标签 % 得到聚类中心与聚类样本标签 function [ClusterCenter,ClusterLabel] = FindCluster(MyData,ClusterCounts,DataLabel) [m,n] = size(MyData); ClusterLabel = zeros(m,1); %用于存储聚类标签 % MyLabel = unique(DataLabel,'rows'); % for i = 1:size(MyLabel,2); % LabelIndex(1,i) = i; %为数据标签创建索引 % end %已知数据集的每个样本的中心 OriginCenter = zeros(ClusterCounts,n); for j = 1:ClusterCounts DataCounts = 0; for i = 1:m %按照数据标签,计算样本中心 if DataLabel(i) == j OriginCenter(j,:) = OriginCenter(j,:) + MyData(i,:); DataCounts = DataCounts + 1; end end OriginCenter(j,:) = OriginCenter(j,:) ./ DataCounts; end %按照第一列对样本中心排序 SortCenter1 = sortrows(OriginCenter,1); FalseTimes = 0; CalcuateTimes = 0; %此循环用于纠正分类错误的情况 while (CalcuateTimes < 15) ClusterCenter = zeros(ClusterCounts,n); %初始化聚类中心 for i = 1:ClusterCounts ClusterCenter(i,:) = MyData( randi(m,1),:); %随机选取一个点作为中心 end %此循环用于寻找聚类中心 %目前还未解决该循环陷入死循环的问题,所以设置一个参数来终止循环 kk = 0; while (kk < 15) Distance = zeros(1,ClusterCounts); %存储单个样本到每个聚类中心的距离 DataCounts = zeros(1,ClusterCounts); %记录每个聚类的样本数目 NewCenter = zeros(ClusterCounts,n); for i = 1:m for j = 1:ClusterCounts Distance(j) = norm(MyData(i,:) - ClusterCenter(j,:)); end %index返回最小距离的索引,亦即聚类中心的标号 [~,index] = min(Distance); ClusterLabel(i) = index; end k = 0; for j = 1:ClusterCounts for i = 1:m %按照标记,对样本进行分类,并计算聚类中心 if ClusterLabel(i) == j NewCenter(j,:) = NewCenter(j,:) + MyData(i,:); DataCounts(j) = DataCounts(j) + 1; end end NewCenter(j,:) = NewCenter(j,:) ./ DataCounts(j); %若新的聚类中心与上一个聚类中心相同,则认为算法收敛 if norm(NewCenter(j,:) - ClusterCenter(j,:)) < 0.1 k = k + 1; end end ClusterCenter = NewCenter; %判断是否全部收敛 if k == ClusterCounts break; end kk = kk + 1 ; end %再次判断每个聚类是否分类正确,若分类错误则进行惩罚 t = ClusterCounts; SortCenter2 = sortrows(ClusterCenter,1); for i = 1:ClusterCounts if norm(SortCenter1(i,:) - SortCenter2(i,:)) > 0.5 t = t - 1; FalseTimes = FalseTimes + 1; break; end end if t == ClusterCounts break; end CalcuateTimes = CalcuateTimes + 1; end % FalseTimes % CalcuateTimes % t % kk % DataCounts % OriginCenter % NewCenter %理论上每个聚类的标签应是123排列的,但实际上,由于每个聚类中心都是随机选取的, %实际分类的顺序可能是213,132等,所以需要对分类标签进行纠正,这对之后的精度评 %价带来了方便。 %对分类标签进行纠正: %算法原理:从第一个已知的样本中心开始,寻找离其最近的聚类中心,然后将归类于该 % 聚类中心的样本的聚类标签更换为i for i = 1:ClusterCounts for j = 1:ClusterCounts if norm(OriginCenter(i,:) - ClusterCenter(j,:)) < 0.6 for p = 1:m if ClusterLabel(p) == j ClusterLabel(p) = 2 * ClusterCounts + i; end end %break; end end end ClusterLabel = ClusterLabel - 2 * ClusterCounts; %Temp = [MyData(:,:),ClusterLabel]
至此已经完成了聚类中心的计算。该方法基本解决了因随机选取初始中心而导致最后聚类中心明显错误的情况,但缺点在于循环太多,时间复杂度O(?),而且目前还未解决偶尔会进入死循环的问题。若判明进入了死循环,还是重新运行下程序吧 = = 。。。
画图的函数(- -):
MyPlot2.m
%函数功能 : 输入样本,样本标签及求出的聚类中心,显示二维图像,实现数据可视化 function MyPlot2(X1,X2,DataLabel,ClusterCenter) [m,~] = size(X1); hold on; for i = 1:m if(DataLabel(i) == 1) plot(X1(i),X2(i),'*r') elseif(DataLabel(i) == 2) plot(X1(i),X2(i),'*g') else plot(X1(i),X2(i),'*b') end end % xlabel(who('X1')); % ylabel(who('X2')); %PS : 我想在坐标轴中根据输入的形参的矩阵的名字,转换成字符串,来动态输出 % 坐标轴名称,不知道该怎么做?用上面注释的语句不行。。 [n,~] = size(ClusterCenter); for i = 1:n plot(ClusterCenter(i,1),ClusterCenter(i,2),'ok') end grid on;MyPlot3.m
function MyPlot3(X1,X2,X3,DataLabels,ClusterCenter) [m,~] = size(X1); hold on; for i = 1:m if(DataLabels(i) == 1) plot3(X1(i),X2(i),X3(i),'.r') elseif(DataLabels(i) == 2) plot3(X1(i),X2(i),X3(i),'.g') else plot3(X1(i),X2(i),X3(i),'.b') end end % xlabel('X1'); % ylabel('X2'); % zlabel('X3'); [n,~] = size(ClusterCenter); for i = 1:n plot3(ClusterCenter(i,1),ClusterCenter(i,2),ClusterCenter(i,3),'ok') end view([1 1 1]); grid on;Accuracy.m 聚类结果精度评价
%函数功能:根据聚类结果进行精度评价 %精度评价,返回每一种分类的精度值(正确率) function ClusterAccuracy = Accuracy(DataLable,CLusterLabel) [m,n] = size(CLusterLabel); ClusterAccuracy = zeros(1,n); %理论上的聚类标签应为 1,2,3,但实际上可能变成了 213 , 132等,导致计算失误 %因此需要对分类标签进行纠正,而这一步骤已经在FindCluster函数中完成了 for i = 1:n %原理:假设某样本在已知数据集中属于第一类,而其聚类后的也同样被分到了第一类,那么它们的标签 %都是1,这样相减后结果就为0,表明已经分类正确,否则不为0,分类错误 Temp(:,i) = DataLable - CLusterLabel(:,i); end for j = 1:n for i = 1:m if Temp(i,j) == 0 ClusterAccuracy(1,j) = ClusterAccuracy(1,j) + 1; end end end ClusterAccuracy = ClusterAccuracy ./ m;
可以看到,在二维的情况下,比较X 3: 花瓣长度(厘米)和X 4:花瓣宽度(厘米)的精度更高(94.67%),也就是说只比较两种特征时,比较 花瓣长度和花瓣宽度,区分三种花的效果更好,分类结果更可靠。
三维分类结果:
可以看到,在三维的情况下,比较X2:萼片宽度(厘米),X3: 花瓣长度(厘米)和X4:花瓣宽度(厘米)的精度更高(93.33%),也就是说比较三种特征时,取X2,X3,X4,区分三种花的效果更好,分类结果更可靠。
最后:本程序目前还存在诸多不足,比如时间复杂度高,效率较低;目前对Matlab语言还不是很熟,写的程序也比较C-Style,各位看官若是有改进的建议,欢迎留言,或者直接联系我(联系方式附在文最末),大家一起探讨:D(手动比心)……
附iris.data数据集:
5.1,3.5,1.4,0.2,Iris-setosa 4.9,3.0,1.4,0.2,Iris-setosa 4.7,3.2,1.3,0.2,Iris-setosa 4.6,3.1,1.5,0.2,Iris-setosa 5.0,3.6,1.4,0.2,Iris-setosa 5.4,3.9,1.7,0.4,Iris-setosa 4.6,3.4,1.4,0.3,Iris-setosa 5.0,3.4,1.5,0.2,Iris-setosa 4.4,2.9,1.4,0.2,Iris-setosa 4.9,3.1,1.5,0.1,Iris-setosa 5.4,3.7,1.5,0.2,Iris-setosa 4.8,3.4,1.6,0.2,Iris-setosa 4.8,3.0,1.4,0.1,Iris-setosa 4.3,3.0,1.1,0.1,Iris-setosa 5.8,4.0,1.2,0.2,Iris-setosa 5.7,4.4,1.5,0.4,Iris-setosa 5.4,3.9,1.3,0.4,Iris-setosa 5.1,3.5,1.4,0.3,Iris-setosa 5.7,3.8,1.7,0.3,Iris-setosa 5.1,3.8,1.5,0.3,Iris-setosa 5.4,3.4,1.7,0.2,Iris-setosa 5.1,3.7,1.5,0.4,Iris-setosa 4.6,3.6,1.0,0.2,Iris-setosa 5.1,3.3,1.7,0.5,Iris-setosa 4.8,3.4,1.9,0.2,Iris-setosa 5.0,3.0,1.6,0.2,Iris-setosa 5.0,3.4,1.6,0.4,Iris-setosa 5.2,3.5,1.5,0.2,Iris-setosa 5.2,3.4,1.4,0.2,Iris-setosa 4.7,3.2,1.6,0.2,Iris-setosa 4.8,3.1,1.6,0.2,Iris-setosa 5.4,3.4,1.5,0.4,Iris-setosa 5.2,4.1,1.5,0.1,Iris-setosa 5.5,4.2,1.4,0.2,Iris-setosa 4.9,3.1,1.5,0.1,Iris-setosa 5.0,3.2,1.2,0.2,Iris-setosa 5.5,3.5,1.3,0.2,Iris-setosa 4.9,3.1,1.5,0.1,Iris-setosa 4.4,3.0,1.3,0.2,Iris-setosa 5.1,3.4,1.5,0.2,Iris-setosa 5.0,3.5,1.3,0.3,Iris-setosa 4.5,2.3,1.3,0.3,Iris-setosa 4.4,3.2,1.3,0.2,Iris-setosa 5.0,3.5,1.6,0.6,Iris-setosa 5.1,3.8,1.9,0.4,Iris-setosa 4.8,3.0,1.4,0.3,Iris-setosa 5.1,3.8,1.6,0.2,Iris-setosa 4.6,3.2,1.4,0.2,Iris-setosa 5.3,3.7,1.5,0.2,Iris-setosa 5.0,3.3,1.4,0.2,Iris-setosa 7.0,3.2,4.7,1.4,Iris-versicolor 6.4,3.2,4.5,1.5,Iris-versicolor 6.9,3.1,4.9,1.5,Iris-versicolor 5.5,2.3,4.0,1.3,Iris-versicolor 6.5,2.8,4.6,1.5,Iris-versicolor 5.7,2.8,4.5,1.3,Iris-versicolor 6.3,3.3,4.7,1.6,Iris-versicolor 4.9,2.4,3.3,1.0,Iris-versicolor 6.6,2.9,4.6,1.3,Iris-versicolor 5.2,2.7,3.9,1.4,Iris-versicolor 5.0,2.0,3.5,1.0,Iris-versicolor 5.9,3.0,4.2,1.5,Iris-versicolor 6.0,2.2,4.0,1.0,Iris-versicolor 6.1,2.9,4.7,1.4,Iris-versicolor 5.6,2.9,3.6,1.3,Iris-versicolor 6.7,3.1,4.4,1.4,Iris-versicolor 5.6,3.0,4.5,1.5,Iris-versicolor 5.8,2.7,4.1,1.0,Iris-versicolor 6.2,2.2,4.5,1.5,Iris-versicolor 5.6,2.5,3.9,1.1,Iris-versicolor 5.9,3.2,4.8,1.8,Iris-versicolor 6.1,2.8,4.0,1.3,Iris-versicolor 6.3,2.5,4.9,1.5,Iris-versicolor 6.1,2.8,4.7,1.2,Iris-versicolor 6.4,2.9,4.3,1.3,Iris-versicolor 6.6,3.0,4.4,1.4,Iris-versicolor 6.8,2.8,4.8,1.4,Iris-versicolor 6.7,3.0,5.0,1.7,Iris-versicolor 6.0,2.9,4.5,1.5,Iris-versicolor 5.7,2.6,3.5,1.0,Iris-versicolor 5.5,2.4,3.8,1.1,Iris-versicolor 5.5,2.4,3.7,1.0,Iris-versicolor 5.8,2.7,3.9,1.2,Iris-versicolor 6.0,2.7,5.1,1.6,Iris-versicolor 5.4,3.0,4.5,1.5,Iris-versicolor 6.0,3.4,4.5,1.6,Iris-versicolor 6.7,3.1,4.7,1.5,Iris-versicolor 6.3,2.3,4.4,1.3,Iris-versicolor 5.6,3.0,4.1,1.3,Iris-versicolor 5.5,2.5,4.0,1.3,Iris-versicolor 5.5,2.6,4.4,1.2,Iris-versicolor 6.1,3.0,4.6,1.4,Iris-versicolor 5.8,2.6,4.0,1.2,Iris-versicolor 5.0,2.3,3.3,1.0,Iris-versicolor 5.6,2.7,4.2,1.3,Iris-versicolor 5.7,3.0,4.2,1.2,Iris-versicolor 5.7,2.9,4.2,1.3,Iris-versicolor 6.2,2.9,4.3,1.3,Iris-versicolor 5.1,2.5,3.0,1.1,Iris-versicolor 5.7,2.8,4.1,1.3,Iris-versicolor 6.3,3.3,6.0,2.5,Iris-virginica 5.8,2.7,5.1,1.9,Iris-virginica 7.1,3.0,5.9,2.1,Iris-virginica 6.3,2.9,5.6,1.8,Iris-virginica 6.5,3.0,5.8,2.2,Iris-virginica 7.6,3.0,6.6,2.1,Iris-virginica 4.9,2.5,4.5,1.7,Iris-virginica 7.3,2.9,6.3,1.8,Iris-virginica 6.7,2.5,5.8,1.8,Iris-virginica 7.2,3.6,6.1,2.5,Iris-virginica 6.5,3.2,5.1,2.0,Iris-virginica 6.4,2.7,5.3,1.9,Iris-virginica 6.8,3.0,5.5,2.1,Iris-virginica 5.7,2.5,5.0,2.0,Iris-virginica 5.8,2.8,5.1,2.4,Iris-virginica 6.4,3.2,5.3,2.3,Iris-virginica 6.5,3.0,5.5,1.8,Iris-virginica 7.7,3.8,6.7,2.2,Iris-virginica 7.7,2.6,6.9,2.3,Iris-virginica 6.0,2.2,5.0,1.5,Iris-virginica 6.9,3.2,5.7,2.3,Iris-virginica 5.6,2.8,4.9,2.0,Iris-virginica 7.7,2.8,6.7,2.0,Iris-virginica 6.3,2.7,4.9,1.8,Iris-virginica 6.7,3.3,5.7,2.1,Iris-virginica 7.2,3.2,6.0,1.8,Iris-virginica 6.2,2.8,4.8,1.8,Iris-virginica 6.1,3.0,4.9,1.8,Iris-virginica 6.4,2.8,5.6,2.1,Iris-virginica 7.2,3.0,5.8,1.6,Iris-virginica 7.4,2.8,6.1,1.9,Iris-virginica 7.9,3.8,6.4,2.0,Iris-virginica 6.4,2.8,5.6,2.2,Iris-virginica 6.3,2.8,5.1,1.5,Iris-virginica 6.1,2.6,5.6,1.4,Iris-virginica 7.7,3.0,6.1,2.3,Iris-virginica 6.3,3.4,5.6,2.4,Iris-virginica 6.4,3.1,5.5,1.8,Iris-virginica 6.0,3.0,4.8,1.8,Iris-virginica 6.9,3.1,5.4,2.1,Iris-virginica 6.7,3.1,5.6,2.4,Iris-virginica 6.9,3.1,5.1,2.3,Iris-virginica 5.8,2.7,5.1,1.9,Iris-virginica 6.8,3.2,5.9,2.3,Iris-virginica 6.7,3.3,5.7,2.5,Iris-virginica 6.7,3.0,5.2,2.3,Iris-virginica 6.3,2.5,5.0,1.9,Iris-virginica 6.5,3.0,5.2,2.0,Iris-virginica 6.2,3.4,5.4,2.3,Iris-virginica 5.9,3.0,5.1,1.8,Iris-virginica
博主联系方式 : QQ:1765928683
邮箱:kelrays@qq.com
2018 / 01 / 27 补充:
我想到了一些提高运行效率的方法,那就是尽量减少for循环,因为matlab对for循环的处理效率是很低的!
可拱参考的优化思路:
1) 使用parfor;
2)使用find;
3)向量化,即使用向量操作代替循环;
4)bsxfun(),sum(), ‘./’ '.*'
5)待补充
2018 / 05 / 03 更新: