数据挖掘 k-means离群点检测
2015-07-07 22:09
507 查看
k-means离群点检测
改写一种简单的半监督方法,用于离群点检测。使用一种你熟悉的程序设计语言,如C++或Java,实现该方法,并在两种不同的数据集上进行讨论(1)只有一些被标记的正常对象;(2)只有一些被标记的离群点实例。一、数据集介绍
1、Iris数据集介绍
iris以鸢尾花的特征作为数据来源,数据集包含150个数据集,分为3类,每类50个数据,每个数据包含4个属性,是在数据挖掘、数据分类中非常常用的测试集、训练集。
三类分别为:setosa, versicolor, virginica。
数据包含4个独立的属性,这些属性变量测量植物的花朵,比如萼片和花瓣的长度等。
2、wine数据集介绍
这份数据集包含来自3种不同起源的葡萄酒的共178条记录。13个属性是葡萄酒的13种化学成分。通过化学分析可以来推断葡萄酒的起源。值得一提的是所有属性变量都是连续变量。数据集特征:多变量;记录数:178;领域:物理;属性特征:整数,实数;属性数目:13。
3、abalone数据集介绍
采用UCI数据集中的abalone数据集进行测试。该数据集包括涉及生活领域的8个类别的4177个数据对象,其中含有1个分类型属性,1个整数型属性和6个实数型属性。分类属性数据对象中含有1528个记录为F(父)值,1307个记录为M(母)值,还有1342个记录为I(未成年人)值。
二、算法描述
K-means算法是很典型的基于距离的聚类算法,采用距离作为相似性的评价指标,即认为两个对象的距离越近,其相似度就越大。该算法认为簇是由距离靠近的对象组成的,因此把得到紧凑且独立的簇作为最终目标。
2.1算法思路
K-means算法
先随机选取K个对象作为初始的聚类中心。然后计算每个对象与各个种子聚类中心之间的距离,把每个对象分配给距离它最近的聚类中心。聚类中心以及分配给它们的对象就代表一个聚类。一旦全部对象都被分配了,每个聚类的聚类中心会根据聚类中现有的对象被重新计算。这个过程将不断重复直到满足某个终止条件。终止条件可以是以下任何一个:
1)没有(或最小数目)对象被重新分配给不同的聚类。
2)没有(或最小数目)聚类中心再发生变化。
3)误差平方和局部最小。
2.2算法步骤
a.从数据集中随机挑K个数据当簇心;
b.对数据中的所有点求到这K个簇心的距离,假如点Pi离簇心Si最近,那么Pi属于Si对应的簇;
c.根据每个簇的数据,更新簇心,使得簇心位于簇的中心;
d.重复步骤e和步骤f,直到簇心不再移动(或其他条件,如前后两次距离和不超过特定值),继续下一步;
e.计算每个簇的正常半径,即阀值(此程序阀值为每个簇的平均距离与1.5倍标准差之和);
f.从每个簇中,找出大于阀值的点,即离群点。
三、java 实现
package kmeans; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; import java.util.Random; public class Kmeans { /** * @param args * @throws IOException */ public static List<ArrayList<ArrayList<Double>>> initHelpCenterList(List<ArrayList<ArrayList<Double>>> helpCenterList,int k){ for(int i=0;i<k;i++){ helpCenterList.add(new ArrayList<ArrayList<Double>>()); } return helpCenterList; } /** * @param args * @throws IOException */ public static void main(String[] args) throws IOException{ List<ArrayList<Double>> centers = new ArrayList<ArrayList<Double>>(); List<ArrayList<Double>> newCenters = new ArrayList<ArrayList<Double>>(); List<ArrayList<ArrayList<Double>>> helpCenterList = new ArrayList<ArrayList<ArrayList<Double>>>(); //读入原始数据 BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream("src/datafile/abaloneNoLabel.data"))); String data = null; List<ArrayList<Double>> dataList = new ArrayList<ArrayList<Double>>(); while((data=br.readLine())!=null){ //System.out.println(data); String []fields = data.split(","); List<Double> tmpList = new ArrayList<Double>(); for(int i=0; i<fields.length;i++) tmpList.add(Double.parseDouble(fields[i])); dataList.add((ArrayList<Double>) tmpList); } br.close(); //随机确定K个初始聚类中心 Random rd = new Random(); int k=3; int [] initIndex={59,71,48}; int [] helpIndex = {0,59,130}; int [] givenIndex = {0,1,2}; System.out.println("random centers' index"); for(int i=0;i<k;i++){ int index = rd.nextInt(initIndex[i]) + helpIndex[i]; 4000 //int index = givenIndex[i]; System.out.println("index "+index); centers.add(dataList.get(index)); helpCenterList.add(new ArrayList<ArrayList<Double>>()); } /* //注释掉的这部分目的是,取测试数据集最后稳定的三个类簇的聚类中心作为初始聚类中心 centers = new ArrayList<ArrayList<Double>>(); for(int i=0;i<59;i++) helpCenterList.get(0).add(dataList.get(i)); for(int i=59;i<130;i++) helpCenterList.get(1).add(dataList.get(i)); for(int i=130;i<178;i++) helpCenterList.get(2).add(dataList.get(i)); for(int i=0;i<k;i++){ ArrayList<Double> tmp = new ArrayList<Double>(); for(int j=0;j<dataList.get(0).size();j++){ double sum=0; for(int t=0;t<helpCenterList.get(i).size();t++) sum+=helpCenterList.get(i).get(t).get(j); tmp.add(sum/helpCenterList.get(i).size()); } centers.add(tmp); } */ //输出k个初始中心 System.out.println("original centers:"); for(int i=0;i<k;i++) System.out.println(centers.get(i)); while(true) {//进行若干次迭代,直到聚类中心稳定 for(int i=0;i<dataList.size();i++){//标注每一条记录所属于的中心 double minDistance=99999999; int centerIndex=-1; for(int j=0;j<k;j++){//离0~k之间哪个中心最近 double currentDistance=0; for(int t=1;t<centers.get(0).size();t++){//计算两点之间的欧式距离 currentDistance += ((centers.get(j).get(t)-dataList.get(i).get(t))/(centers.get(j).get(t)+dataList.get(i).get(t))) * ((centers.get(j).get(t)-dataList.get(i).get(t))/(centers.get(j).get(t)+dataList.get(i).get(t))); } if(minDistance>currentDistance){ minDistance=currentDistance; centerIndex=j; } } helpCenterList.get(centerIndex).add(dataList.get(i)); } // System.out.println(helpCenterList); //计算新的k个聚类中心 for(int i=0;i<k;i++){ ArrayList<Double> tmp = new ArrayList<Double>(); for(int j=0;j<centers.get(0).size();j++){ double sum=0; for(int t=0;t<helpCenterList.get(i).size();t++) sum+=helpCenterList.get(i).get(t).get(j); tmp.add(sum/helpCenterList.get(i).size()); } newCenters.add(tmp); } System.out.println("\nnew clusters' centers:\n"); for(int i=0;i<k;i++) System.out.println(newCenters.get(i)); //计算新旧中心之间的距离,当距离小于阈值时,聚类算法结束 double distance=0; for(int i=0;i<k;i++){ for(int j=1;j<centers.get(0).size();j++){//计算两点之间的欧式距离 distance += ((centers.get(i).get(j)-newCenters.get(i).get(j))/(centers.get(i).get(j)+newCenters.get(i).get(j))) * ((centers.get(i).get(j)-newCenters.get(i).get(j))/(centers.get(i).get(j)+newCenters.get(i).get(j))); } //System.out.println(i+" "+distance); } System.out.println("\ndistance: "+distance+"\n\n"); if(distance==0)//小于阈值时,结束循环 break; else//否则,新的中心来代替旧的中心,进行下一轮迭代 { centers = new ArrayList<ArrayList<Double>>(newCenters); //System.out.println(newCenters); newCenters = new ArrayList<ArrayList<Double>>(); helpCenterList = new ArrayList<ArrayList<ArrayList<Double>>>(); helpCenterList=initHelpCenterList(helpCenterList,k); } } //输出最后聚类结果 for(int i=0;i<k;i++){ System.out.println("\n\nCluster: "+(i+1)+" size: "+helpCenterList.get(i).size()+" :\n\n"); for(int j=0;j<helpCenterList.get(i).size();j++) { // System.out.println(helpCenterList.get(i).get(j)); } } int dataSetLength=dataList.size(); double[][] distance = new double[k][dataSetLength]; double[] distanceSum=new double[k]; for(int j=0;j<k;j++) { for (int i = 0; i < helpCenterList.get(j).size(); i++) { distance[j][i] = distance(helpCenterList.get(j).get(i), centers.get(j)); distanceSum[j]+= distance[j][i]; } //每个簇的平均距离 distanceSum[j]/= helpCenterList.get(j).size(); System.err.println(distanceSum[j]); double radius=distanceSum[j]+1.5*Standardlizerdistance(distance[j],distanceSum[j]); System.err.println("\n\nCluster: "+(j+1)+" 每个簇的正常半径,即阀值(此程序阀值为每个簇的平均距离与1.5倍标准差之和为: "+radius); for(int i=0;i<helpCenterList.get(j).size();i++) { if(distance[j][i]>radius) { System.err.println(helpCenterList.get(j).get(i)+"离群 "+distance[j][i]); } // else // System.out.println(helpCenterList.get(j).get(i)+"正常半径: "+distance[j][i]); } } } private static double distance(ArrayList<Double> element, ArrayList<Double> center) { double currentDistance=0; for(int t=1;t<element.size();t++){//计算两点之间的欧式距离 currentDistance += (element.get(t)-center.get(t))*(element.get(t)-center.get(t)); } return Math.sqrt(currentDistance); } private static double Standardlizerdistance(double[] distance, double x) { double currentDistance=0; for(int t=1;t<distance.length;t++){//计算两点之间的欧式距离 currentDistance += (distance[t]-x)*(distance[t]-x); } return Math.sqrt(currentDistance/distance.length); } }
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树
- [原创]java局域网聊天系统