数据挖掘 k-means离群点检测

原创 2015年07月07日 22:09:38

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];
            //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);
    }
}

基于聚类的离群点检测

在利用R软件进行数据挖掘时,离群点检测经常是必不可少的一部分。离群点检测的任务是发现与大部分其它对象显著不同的对象。大部分数据挖掘方法都将这种差异信息视为噪声丢弃,然而在部分情况下,罕见的数据可能蕴含...

数据挖掘笔记(3)——聚类、离群点分析

聚类 基本概念 聚类:       将对象分成相似的类 特征:       不考虑数据的类标号,而是通过聚类产生新类标号 评价:         最大化类内相似性(similarit...

异常点/离群点检测算法——LOF

原文链接地址:http://blog.csdn.net/wangyibo0201/article/details/51705966在数据挖掘方面,经常需要在做特征工程和模型训练之前对数据进行清洗,剔除...

离群点检测Outlier Detection

http://www.dataivy.cn/blog/%E7%A6%BB%E7%BE%A4%E7%82%B9%E6%A3%80%E6%B5%8Boutlier-detection/ 在《...
  • scdxmoe
  • scdxmoe
  • 2016年12月19日 15:53
  • 3388

离群点检验方法

离群点离群点(outlier)是一个数据对象,它显著不同于其他数据对象,好像它是被不同的机制产生一样。离群点检验就是找出其行为很不同于预期对象的过程。应用:信用卡欺诈离群点类型离群点类型: 全局离群点...

基于密度的局部离群点检测(lof算法) (Java 实现)

算法:基于密度的局部离群点检测(lof算法) 输入:样本集合D,正整数K(用于计算第K距离) 输出:各样本点的局部离群点因子 过程: 1,    计算每个对象与其他对象的欧几里得距离 2,    对欧...

用matlab实现一个简单的离群点挖掘(与时序有关)

在视频分析中,需要用到离群点挖掘,下面给出一个简单的离群点挖掘, matlab代码如下:   clear clc orgX = [1 1 0 3 4 5 2 70 100 100 100 6 60...
  • stpeace
  • stpeace
  • 2012年11月13日 12:08
  • 2502

用matlab实现一个简单的离群点挖掘(与时序无关)

有时候,在视频特征分析中,要用到离群点挖掘,现给出一个简单的离群点挖掘的例子. 设向量为x = [1  1.1  1.2  1.3  1.4  2 0.2  1.2  1.3  1.4  0.9  1...
  • stpeace
  • stpeace
  • 2012年11月08日 18:52
  • 5316

异常点/离群点检测算法——LOF

局部异常因子算法-Local Outlier Factor(LOF)  在数据挖掘方面,经常需要在做特征工程和模型训练之前对数据进行清洗,剔除无效数据和异常数据。异常检测也是数据挖掘的一个方向,用于反...

线性拟合——离群点outliers的处理

问题考虑如下的数据集:x,yx,y 是观测到的变量(observed variables),yy的误差存放在数组 ee 中:x = np.array([ 0, 3, 9, 14, 15, 19, ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:数据挖掘 k-means离群点检测
举报原因:
原因补充:

(最多只允许输入30个字)