模式识别实验报告.docx
《模式识别实验报告.docx》由会员分享,可在线阅读,更多相关《模式识别实验报告.docx(23页珍藏版)》请在冰豆网上搜索。
模式识别实验报告
武汉大学国际软件学院
实验报告
课程名称模式识别导论
专业年级2015级
姓名宁佳星
学号2015302580323
协作者
实验学期2017-2018学年上学期
课堂时数0课外时数12
填写时间2017年11月12日
实验概述
【实验项目名称】:
模式识别作业1
【实验目的】:
1、请编写程序实现混合类型属性差异性矩阵计算
2、请编写程序实现近邻聚类算法或者最大最小距离聚类算法
3、请编写程序实现层次聚类算法
4、请编写程序实现K-means或者K-中心点聚类算法
5、请编写程序实现ISODATA算法
6、使用统一的测试数据观察不同算法的聚类结果,并讨论为什么
【实验环境】(使用的软件):
●Windiws7
●VisualStudio2017
【参考资料】:
●《模式识别作业1》
●模式识别PPT
●网络索引
实验内容
【实验方案设计】:
1、编写程序实现混合类型属性差异性矩阵计算
//矩阵三元组之矩阵相加相乘
...
#defineMAXSIZE12500//最大非零元素
...
voidInputMatrix(TSMatrix&T)//输入t个非零元素
{
...
}
...
voidTransposeSMatrix(TSMatrixM,TSMatrix&T)//矩阵的转置
{
...
}
...
voidAddMastrix(TSMatrixM,TSMatrixT,TSMatrix&Q)//矩阵相加
{
...
}
...
//for循环复制剩余元素
...
voidMultiply(TSMatrixM,TSMatrixT,TSMatrix&Q)//矩阵相乘
{
...
int*rowSize=newint[T.mu+1];//存放每行非零元素的个数
int*rowStart=newint[T.mu+2];//矩阵每行在三元组开始位置
int*temp=newint[T.nu+1];//存放结果矩阵中每行的计算结果
...
while(Current<=M.tu)
{
ROWM=M.data[Current].row;//当前三元组数据中元素的行号
...
while(Current<=M.tu&&ROWM==M.data[Current].row)
{
COLM=M.data[Current].col;//当前元素的列号,方便与T矩阵的行号相乘
for(i=rowStart[COLM];i...
}
}
...
2、编写程序实现近邻聚类算法或者最大最小距离聚类算法
//最大最小距离聚类算法
...
constintN=15;//设置样本点个数
...
voidmain(void)
{
...
floats[2][N]={{0,1,0,-1,0,10,11,9,10,10,-10,-11,-9,-10,-10},
{0,0,1,0,-1,0,0,0,1,-1,0,0,0,1,-1}};//输入样本点
...
center[0]=0;//firstcenter
...
center[1]=index;//secondcenter
...
//求出所有中心,finalarraymin[]isstilluseful
while(theshold>theta*D12)
{
...
//min-operate
for(j=0;j{
...
}
...
if(max>theta*D12){k++;center[k]=index;}//addacenter
theshold=max;//preparetoloopnexttime
}
...
}
3、编写程序实现层次聚类算法
//实现层次聚类算法
...
//计算两个样本点之间的欧几里得距离
doubleCAgeneCluster:
:
getDistance(sDataPointdpA,sDataPointdpB)
{
...
}
list*CAgeneCluster:
:
initialCluster(list*dataPoints)
{
...
{
sDataPointtempDataPoint=*iter;//取出数据,
...
tempCluster.clusterLabel=i;//初始类簇号为各原数据顺序号
tempCluster.datapointList->push_back(tempDataPoint);
//每一个数据为一类
originalClusters->push_back(tempCluster);//originalClusters为类簇序列
...
}
...
}
list*CAgeneCluster:
:
mergeCluster(list*clusters,intmergeIndexA,intmergeIndexB)//mergeIndexA,B是类簇标号
{
...
intnBreak=0;//计算找到的次数,以提前退出循环,节省时间
if(mergeIndexA!
=mergeIndexB)//分属于不同的类簇,则合并.
{//将cluster[mergeIndexB]中的DataPoint加入到cluster[mergeIndexA]
for(list:
:
iteratoriter=clusters->begin();iter!
=clusters->end();iter++)
{//把mergeIndexA所在类簇提取出来。
tempCluster=*iter;//以下程序找出mergeIndexAandB所在类簇,并从链表中删除B类簇。
if(tempCluster.clusterLabel==mergeIndexA)
{
nBreak++;//计算找到的次数,以提前退出循环,节省时间
tempClusterA=*iter;
}//endforif(tempCluster.clusterLabel==mergeIndexA)
if(tempCluster.clusterLabel==mergeIndexB)
{//并从链表中删除B类簇。
tempClusterB=*iter;
nBreak++;//计算找到的次数,以提前退出循环,节省时间
...
if(nBreak==2)
{//找到两个类簇,则提前退出循环,节省时间。
nBreak=0;
break;
}
}
...
dpA=tempClusterA.datapointList;//把clusterA中的数据集提取出来。
...
for(list:
:
iteratoriter=dpB->begin();iter!
=dpB->end();iter++)
{//取出数据
dpA->push_back(*iter);//把B中数据存入到A.
}
...
}
...
}
list*CAgeneCluster:
:
startAnalysis(list*dataPoints,unsignedintClusterNum)
{
...
originalClusters=initialCluster(dataPoints);//数据集初始化;//originalClusters为类簇序列
...printCluster(originalClusters);//打印聚类情况
...
while(finalClusters->size()>ClusterNum)//聚类数为ClusterNum
{
doubleminDist=9999999.9999;//maxvalue
...
{
...
if(iIter!
=jIter)
{
...
dataPointsA=ClusterA.datapointList;//类簇中的数据集
clusterLabelA=ClusterA.clusterLabel;//类簇标号
dataPointsB=ClusterB.datapointList;//类簇中的数据集
clusterLabelB=ClusterB.clusterLabel;//类簇标号
for(list:
:
iteratoriterdpA=dataPointsA->begin();iterdpA!
=dataPointsA->end();iterdpA++)
{
...
if(tempDis{
minDist=tempDis;//每次都是距离最小的两个合并。
...
}
...
}
cout<<"mergeIndexA="<finalClusters=mergeCluster(finalClusters,mergeIndexA,mergeIndexB);//mergeIndexA,B是类簇标号
printCluster(originalClusters);//打印聚类情况
}
...
}
...
4、编写程序实现K-means或者K-中心点聚类算法
//K-means聚类算法
...
constintNUM=3;//定义划分簇的数目
//数据向量表示
...
//计算距离的平方
doublegetDist(VectA,VectB)
{
...
}
//计算每个簇的中心,平均距离表示
VectgetMeansC(vectort)
{
...
for(inti=0;i{
...
}
Vectc;
...
}
//获取算法的准则函数值,当准则函数收敛时算法停止
doublegetE(vectorclasses[],Vectmeans[])
{
...
for(inti=0;i{
...
}
...}
intsearchMinC(Vectt,Vectmeans[],intn,double*D)
{
...
for(inti=1;i{
...
}
...
}
//找最优的种子点
voidFind(vectorinit,Vectmeans[])
{
...
for(inti=1;i{
...
for(intj=0;j{
...
}
...
for(intj=0;j{
...
}
}
...}
voidkMeans(vectorinit)
{
...
newE=getE(classes,means);//计算当前准则函数值
for(inti=0;i...
while(fabs(newE-oldE)>=1)
{
for(inti=0;i{
...
}
...
}
//输出最终结果
for(inti=0;i{
...
}
//每个类的中心点坐标
for(inti=0;i...
}
...
5、编写程序实现ISODATA算法
//ISODATA算法
...
#defineiniClusters5//初始类聚的个数
...//定义6个使用的参数
structArgs
{
intexpClusters;//期望得到的聚类数
intthetaN;//聚类中最少样本数
intmaxIts;//最大迭代次数
intcombL;//每次迭代允许合并的最大聚类对数
doublethetaS;//标准偏差参数
doublethetaC;//合并参数
}args;
//定义二维点,这里假设是二维的特征,当然可以推广到多维
structPoint
{
doublex,y;
};
//需要合并的两个类聚的信息,包括两个类聚的id和距离
structMergeInfo
{
intu,v;
doubled;//类聚u中心与类聚v中心的距离
};
//定义比较函数
boolcmp(MergeInfoa,MergeInfob)
{
returna.d}
//计算两点之间距离
doubledist(PointA,PointB)
{
returnsqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}
structCluster
{
intnSamples;//样本点的个数
doubleavgDist;//样本点到样本中心的平均距离
Pointcenter;//样本中心
Pointsigma;//样本与中心的标准差
vectordata;//聚类的数据
//计算该聚类的中心,即该类的均值
voidcalMean()
{
...
}
//计算该类样本点到该聚类中心得平均距离
voidcalDist()
{
...
}
//计算样本与中心的标准差
voidcalStErr()
{
...
}
};
//获取数据
voidgetData(Pointp[],intn)
{
...
}
//设置参数的值
voidsetArgs()
{
...
}
//寻找点t距离最近的类的中心对应的id
intFindIdx(vector&c,Point&t)
{
...
}
//二分法寻找距离刚好小于thetaC的两个类聚的index
intFindPos(MergeInfo*info,intn,doublethetaC)
{
...
}
...
voidISOData(Pointp[],intn)
{
...
intnClusters=iniClusters;//初始化类聚个数
//初始化nClusters个类,设置相关数据
...
boolisLess=false;//标志是否有类的数目低于thetaN
while
(1)
{
//先清空每一个聚类
for(inti=0;i{
...
}
//将所有样本划分到距离类聚中心最近的类中
...
intk=0;//记录样本数目低于thetaN的类的index
for(inti=0;i{
if(c.at(i).data.size(){
isLess=true;//说明样本数过少,该类应该删除
...
}
}
//如果有类的样本数目小于thetaN
if(isLess)
{
...
}
//重新计算均值和样本到类聚中心的平均距离
for(inti=0;i{
...
}
//计算总的平均距离
...
//分裂操作
if(nClusters<=args.expClusters/2)
{
...
for(inti=0;i{
//计算该类的标准偏差
c.at(i).calStErr();
//计算该类标准差的最大分量
doublemt=c.at(i).sigma.x>c.at(i).sigma.y?
c.at(i).sigma.x:
c.at(i).sigma.y;
maxsigma.push_back(mt);
}
...
{
nClusters++;
ClusternewCtr;//新的聚类中心
//获取新的中心
...
//改变老的中心
...
}
...
}
//合并操作
if(nClusters>=2*args.expClusters||(iter&1)==0)
{
intsize=nClusters*(nClusters-1);
//需要合并的聚类个数
...
//进行排序
sort(info,info+cnt,cmp);
//找出info数组中距离刚好小于thetaC的index,那么index更小的更应该合并
intiPos=FindPos(info,cnt,args.thetaC);
//用于指示该位置的样本点是否已经合并
bool*flag=newbool[nClusters];
memset(flag,false,sizeof(bool)*nClusters);
//用于标记该位置的样本点是否已经合并删除
bool*del=newbool[nClusters];
memset(del,false,sizeof(bool)*nClusters);
//记录合并的次数
intnTimes=0;
for(inti=0;i<=iPos;i++)
{
...
//确保同一个类聚只合并一次
if(!
flag[u]&&!
flag[v])
{
nTimes++;
//如果一次迭代中合并对数多于combL,则停止合并
if(nTimes>bL)break;
//将数目少的样本合并到数目多的样本中
if(c.at(u).nSamples...
}
//删除合并后的聚类
vector:
:
iteratorid=c.begin();
...
//合并多少次就删除多少个
...
}
...
}
intmain()
...
6、用统一的测试数据观察不同算法的聚类结果,并讨论为什么
1中矩阵运算的试验数据见下图(结果)
2-5中使用同同样的样本点数据测试,详情见下图,分析见小结
相关数据:
【结论】(结果):
1、编写程序实现混合类型属性差异性矩阵计算
2、编写程序实现近邻聚类算法或者最大最小距离聚类算法
3、编写程序实现层次聚类算法
4、编写程序实现K-means或者K-中心点聚类算法
5、编写程序实现ISODATA算法
【小结】:
●实验要求算法基本实现,经完善后可正常运行计算
●关于2-5中不同算法对相同数据的运算得到了略有有差别的结果
●聚类的目标是使同一类对象的相似度尽可能地大;不同类对象之间的相似度尽可能地小
●不同算法的根本思想具有一定的差异,因此导致了计算结果的差异
●例如层次聚类
●优点:
适用于任意形状和任意属性的数据集;灵活控制不同层次的聚类粒度,强聚类能力
●缺点:
大大延长了算法的执行时间,不能回溯处理
●例如K-means算法
●优点:
应用广泛;收敛速度快;能扩展以用于大规模的数据集
●缺点:
倾向于识别凸形分布、大小相近、密度相近的聚类;中心选择和噪声聚类对结果影响大
●ISODATA算法是一种常用的聚类分析方法,是一种非监督学习方法。
ISODATA算法通过设置初始参数而引入人机对话环节,并使用归并和分裂等机制,当两类聚中心小于某个阀值时,将它们合并为一类。
当某类的标准差大于某一阀值时或其样本数目超过某一阀值时,将其分裂为两类,在某类样本数目小于某一阀值时,将其取消。
这样根据初始类聚中心和设定的类别数目等参数迭代,最终得到一个比较理想的分类结果。
指导教师评语及成绩
【评语】:
成绩:
指导教师签名:
批阅日期:
附件:
实验报告说明
1.实验项目名称:
要用最简练的语言反映实验的内容。
要求与实验指导书中相一致。
2.实验目的:
目的要明确,要抓住重点,符合实验任务书中的要求。
3.实验环境:
实验用的软硬件环境(配置)。
4.实验方案设计(思路、步骤和方法等):
这是实验报告极其重要的内容。
包括概要设计、详细设计和核心算法说明及分析,系统开发工具等。
应同时提交程序或设计电子版。
对于设计型和综合型实验,在上述内容基础上还应该画出流程图、设计思路和设计方法,再配以相应的文字