大数据挖掘聚类算法课程设计报告材料.docx
《大数据挖掘聚类算法课程设计报告材料.docx》由会员分享,可在线阅读,更多相关《大数据挖掘聚类算法课程设计报告材料.docx(17页珍藏版)》请在冰豆网上搜索。
大数据挖掘聚类算法课程设计报告材料
数据挖掘聚类问题(PlantsDataSet)实验报告
1.数据源描述
1.1数据特征
本实验用到的是关于植物信息的数据集,其中包含了每一种植物(种类和科属)以及它们生长的地区。
数据集中总共有68个地区,主要分布在美国和加拿大。
一条数据(对应于文件中的一行)包含一种植物(或者某一科属)及其在上述68个地区中的分布情况。
可以这样理解,该数据集中每一条数据包含两部分内容,如下图所示。
图1数据格式
例如一条数据:
abroniafragrans,az,co,ks,mt,ne,nm,nd,ok,sd,tx,ut,wa,wy。
其中abroniafragrans是植物名称(abronia是科属,fragrans是名称),从az一直到wy是该植物的分布区域,采用缩写形式表示,如az代表的是美国Arizona州。
植物名称和分布地区用逗号隔开,各地区之间也用逗号隔开。
1.2任务要求
聚类。
采用聚类算法根据某种特征对所给数据集进行聚类分析,对于聚类形成的簇要使得簇内数据对象之间的差异尽可能小,簇之间的差距尽可能大。
2.数据预处理
2.1数据清理
所给数据集中包含一些对聚类过程无用的冗余数据。
数据集中全部数据的组织结构是:
先给出某一科属的植物及其所有分布地区,然后给出该科属下的具体植物及其分布地区。
例如:
abelmoschus,ct,dc,fl,hi,il,ky,la,md,mi,ms,nc,sc,va,pr,vi
abelmoschusesculentus,ct,dc,fl,il,ky,la,md,mi,ms,nc,sc,va,pr,vi
abelmoschusmoschatus,hi,pr
上述数据中第行给出了所有属于abelmoschus这一科属的植物的分布地区,接下来的两行分别列出了属于abelmoschus科属的两种具体植物及其分布地区。
从中可以看出后两行给出的所有地区的并集正是第一行给出的地区集合。
在聚类过程中第行数据是无用的,因此要对其进行清理。
2.2数据变换
本实验是依据植物的分布区域进行聚类,所给数据集中的分布区域是字符串形式,不适合进行聚类,因此将其变换成适合聚类的数值形式。
具体思想如下:
数据集中总共包含68个区域,每一种植物的分布区域是这68个区域中的一部分。
本实验中将68个区域看成是数据对象的68个属性,这68个属性是二元类型的变量,其值只能去0或者1。
步骤如下:
1.把68个区域按一定顺序存放在字符串数组(记为str)中(顺序可以自己定,确定后不能改变)。
2.为数据集中的每个数据对象设置一个长度为68字符串数组,初始元素值全为0。
将数据对象的分布区域逐个与str中的所有元素比较。
如果存在于str中下标i的位置,就将该数据对象的字符串数组的第i位置为1。
例如,一个数据对象为:
abiesfraseri,ga,nc,tn,va。
其分布区域包含ga,nc,tn和va四个地区,将这四个地区逐个与str中全部68个元素比较。
假设这四个地区分别存在于str中的第0,1,2,3位置,则将为该数据对象设置的字符串数组中第0,1,2,3位置全部置为1。
★数据预处理代码(包括数据清理和数据变换):
publicArrayListgetRaw_DataSet(){
ArrayListraw_dataSet=newArrayList();//定义集合存储从本地获取的数据
BufferedReaderbufferedReader=null;
FileReaderfileReader=null;
FiledataFile=newFile(this.fileName);
if(dataFile.exists()){//如果数据文件存在
try{
fileReader=newFileReader(this.fileName);
bufferedReader=newBufferedReader(fileReader);
Stringdata=null;
while((data=bufferedReader.readLine())!
=null){
if(isRightData(data))
raw_dataSet.add(data);
}
}catch(Exceptione){
e.printStackTrace();
}
}else
this.isFileExit=false;
returnraw_dataSet;
}//getRaw_DataSet,从本地txt文件获取数据集
publicArrayListgetFinished_DataSet(){//获取经过预处理,用来进行聚类的数据
ArrayListfinished_DataSet=newArrayList();
ArrayListtemp_DataSet=this.getRaw_DataSet();
for(inti=0;iArrayListeachRomItem=null;
eachRomItem=this.spilt(temp_DataSet.get(i),',');//除去","后的每一行数据
DataItemdata_Item=newDataItem(eachRomItem,true);
finished_DataSet.add(data_Item);
}//for
returnfinished_DataSet;
}
publicbooleanisRightData(Stringdata){//筛选出合适的数据
ArrayListtempArrayList=newArrayList();
tempArrayList=spilt(data,'');
if(tempArrayList.size()<=1)
returnfalse;
returntrue;
}//isRightData,筛选出合适的数据
publicArrayListspilt(Stringstr,charch){
ArrayListwords=newArrayList();//用来存放找到的单词
intbeginIndex=0;
for(inti=0;iif(str.charAt(i)!
=ch){
if(i!
=str.length()-1)
continue;
else{
words.add(str.substring(beginIndex));
}
}else{
Stringtemp=str.substring(beginIndex,i);
words.add(temp);
beginIndex=i+1;
}
}//for
returnwords;
}
3.聚类分析
3.1算法描述
本实验采用了聚类分析中常用的K均值(K-Means)算法。
该算法思想如下:
算法:
K均值。
用于划分的K均值算法,每个簇的中心用簇中对象的均值表示。
输入:
■k:
簇的属目
■D:
包含n个对象的数据集。
输出:
k个簇的集合。
方法:
(1)从D中任意选择k个对象作为初始簇中心;
(2)repeat
(3)根据簇中对象的均值,将每个对象(再)指派到最相似的簇;
(4)更新簇均值,既计算每个簇中对象的均值;
(5)until不再发生变化
开始
从本地读取数据文件
数据预处理
输入k,簇的个数
在数据集中随机选取k个数据对象作为初始中心点
迭代开始。
将数据集中每个数据对象与k个中心点作比较,把每个对象分到与其最相似的中心点所在的簇中
计算每个簇中对象的均值,作为该簇新的中心点
满足迭代终止条件
迭代终止,输出结果。
根据上述算法,结合本实验实际情况和数据集特征给出程序的执行流程图:
否
是
图2程序执行流程
针对上面的流程图,有几点说明:
1.数据预处理主要包括前述数据清理和数据变换,最终生成用于聚类分析的数据集。
2.簇的个数k由用户指定,k越大聚类过程耗时越久。
3.图中“最相似”意思就是距离中心点距离最近,本实验中采用欧几里得距离,其定义如下:
其中
和
是两个n维数据对象。
在本实验中,
和
分别代表为i,j两个数据对象设置的字符串数组(参看2.2)中下标为1的元素值,此处n为68。
4.流程图中的终止条件指的是:
前后两次中心点之间的距离(仍然用欧几里得距离)是否小于设定的值。
例如,第n次迭代完成后重新生成了k个新的中心点,计算k个新中心点与k个旧的中心点距离之和并将结果与设定的值比较,若小于设定值则终止迭代,聚类完成,否则继续迭代。
3.2算法实现
图3代码文件的组织结构
上图是本实验源码的组织结构,该项目包含五个Java类。
每个类的功能描述如下:
◆Cluster.java类该类定义了簇的结构,包含簇标志,簇成员和簇中心点三个字段。
该类的每一个实例对应于聚类过程中的一个簇。
◆DataItem.java类该类定义了数据对象的结构,主要包含数据对象名称(即植物名称)和数据对象字符串数组(即植物的分布区域)。
该类的每一个实例对应于数据集中的一个数据对象。
◆Main.java类该类是程序的核心类,主要功能是执行聚类过程,包括中心点的选取与更新,计算各个数据对象与中心点之间的距离并把其派分到最相似的簇等。
◆ReadData.java类该类主要功能是生成聚类过程适用的数据集,包括读取文件,数据预处理等。
◆Tools.java类该类是一个工具类,其中定义了多个程序中使用到的静态方法。
★Mian.java类中的核心代码:
(1)随机选取中心点
publicvoidsetCenter_ran(){//第一次,从数据集中随机选取中心点
beginTime=System.currentTimeMillis();
System.out.println("聚类过程开始,开始于:
"+Tools.currentTime());
Randomran=newRandom();
intorder=0;//随机选取中心点
while(this.center.size()order=ran.nextInt(toBeProcessed.size());
if(Tools.isProCener(toBeProcessed.get(order),this.center))
this.center.add(toBeProcessed.get(order));
}//while
}
(2)初始化簇集合
publicvoidinitArrayCluster(ArrayListcenter){//初始每个簇中的中心点属性
this.arrayCluster.clear();//把簇集合清空
for(inti=0;i
Clustercluster=newCluster(i,center.get(i));
if(this.center.get(i).getIsDataItem())
cluster.addMembers(center.get(i));
this.arrayCluster.add(cluster);
}
}
(3)执行聚类过程(计算距离,把数据对象派分到最相似簇中)
publicvoidrunCluster(ArrayListcenter){
intbeyondIndex=0;//判断数据项属于哪一个簇,初始默认为是0簇
Randomrd=newRandom();//随机函数
printBeginInfo();//打印以此迭代开始前的信息。
for(inti=0;ibeyondIndex=0;
booleanisAlreadyExitInCluster=true;//标记当前处理的数据对象是否已经存在于某个簇中
doubleminDistance=Tools.calcDistance(toBeProcessed.get(i),
center.get(0),0);
intranIndex=rd.nextInt(center.size());//随机产生一个中心点集合的索引
for(intj=0;j
if(center.contains(toBeProcessed.get(i)))//如果正在处理的数据对象存在于中心点集合中,则跳出循环
break;
isAlreadyExitInCluster=false;
if(ranIndex>=center.size())
ranIndex=ranIndex%center.size();
doublecorrentDistance=Tools.calcDistance(
toBeProcessed.get(i),center.get(ranIndex),0);
if(correntDistanceminDistance=correntDistance;
beyondIndex=ranIndex;
}//第二个if
ranIndex++;
}//第二个for
if(!
isAlreadyExitInCluster){
this.arrayCluster.get(beyondIndex).addMembers(
toBeProcessed.get(i));//把数据对象加入到对应的簇中
}
}//第一个for
System.out.println("第"+this.count+"次迭代完成。
");
printClusteringInfo();
}
(4)迭代过程(产生新的中心点,继续执行聚类过程直至满足终止条件)
publicvoidfinishCluster(){
DecimalFormatdf=newDecimalFormat("##.000");//格式化数据,保留三位小数
for(inti=0;idoublemoveDistance=0.0;//存放各个簇新旧中心点欧几里得距离之和
//重新计算簇中心点
for(intj=0;jbooleanisEmptyCluster=true;
DataItemnewCenterItem;//声明新的中心点对象
intsize=this.arrayCluster.get(j).getMembers().size();
double[]newCenterArea=newdouble[NUMOFAREA];
//计算簇中数据的均值
for(intindex=0;indexdoubletempValue=0.0;//暂存每一列区域值的加和
for(intk=0;kisEmptyCluster=false;
tempValue+=this.arrayCluster.get(j).getMembers()
.get(k).getAreas()[index];
}
if(!
isEmptyCluster){
newCenterArea[index]=Double.valueOf(df
.format(tempValue/size));
}else
break;
}//第三个for
if(!
isEmptyCluster){//如果簇不为空
Stringname="cluster"+j;
newCenterItem=newDataItem(name,newCenterArea,false);//新的簇中心点对象
DataItemoldCenter=this.center.get(j);//获取旧的簇中心点
moveDistance+=Tools.calcDistance(oldCenter,
newCenterItem,0);//计算新旧中心点移动的距离
this.center.remove(j);//更新簇中心点集合
this.center.add(j,newCenterItem);
}
}//第二个for,重新计算簇中心
//System.out.println(this.center.toString());//打印新的中心点信息
if(moveDistancebreak;
}
count++;
initArrayCluster(this.center);
runCluster(this.center);
}//第一个for
}
3.3问题与改进
聚类分析要求不同簇之间的距离尽可能大,初始随机选取的中心点并不能保证不同中心点之间的距离尽可能远,本程序对算法进行改进,在随机选取中心点时要求与已经选取的中心点之间的距离大于设定值。
这样做保证了随机选取的中心点相对比较分散,提高了聚类效果。
主要代码如下:
publicstaticbooleanisProCener(DataItemcenterItem,//判断是不是合适的中心点
ArrayListcenter){
if(center.size()>0){//如果当前的中心点集合不为空
for(inti=0;i
if(Tools.calcDistance(centerItem,center.get(i),0)returnfalse;
}
if(center.contains(centerItem))
returnfalse;
}
returntrue;
}
4.开发与运行环境配置
●操作系统:
Windows7
●开发工具:
Eclipse
●开发语言:
Java
●CPU频率:
2.2GHz
●内存:
3.5GB
两种运行方式:
解压源程序,将PlantsClustering工程导入Eclipse即可运行;直接运行打包生成的exe文件。
两种方式均要求电脑上安装有JDK1.5或更高版本。
5.程序运行情况分析
5.1运行截图
图4指定数据文件并输入聚类簇数
程序运行开始时需要用户指定数据文件的路径,不指定的话默认是D盘根目录下的plants.data.txt文件。
之后需要用户输入聚类产生的簇数,簇数介于1到100之间。
图5迭代过程,输出中心点信息
每次迭代会输出本次迭代的中心点信息。
上图是第一次迭代的部分中心点信息(总共有50个中心点)。
图6第一次迭代后簇的信息图7簇的信息和终止条件的判定
一次迭代完成后会输出本次迭代后各簇的信息并计算新旧中心点的移动距离,与设定的值比较,判定是否继续迭代。
图8把簇的信息保存到本地
满足终止条件,迭代结束,此时会在D:
\DataMining\目录下生成保存各个簇信息的文件,里面是该簇中包含的数据对象。
5.2聚类效果分析
聚类分析要求得到的簇之间相异度尽可能大,簇内的数据对象相异度尽可能小。
本程序会在聚类分析完成后会输出各簇内的平均距离和簇间平均距离,作为对聚类效果评判的参考。
如下截图:
图9聚类效果
5.3总结
K均值聚类算法的效果与簇数和初始中心点有关。
初始中心点选取应尽可能分散。
簇数越多聚类效果越好,但同时程序运行的时间开销也会加大,平衡二者找到一个合适的k是该算法的一个重点。