资源下载

#本文PDF版下载

C#下实现的K-Means优化[1]-「离群点检测」

前言

在上一篇博文中,我和大家分享了「C # 下实现的多维基础K-MEANS聚类」的[C#下实现的基础K-MEANS多维聚类 - xlxw - 博客园].在上篇文章中使用的是最传统的K-Means均值聚类方法,在上文中只是介绍了有一些能优化的方法但是没有具体的讲怎么去优化.所以在这篇博文中,我会和大家分享.我学到的关于我们前面说的聚类前的预处理-离群点的检测.

离群点的检测方法

离群点的检测是数据挖掘中很重要的部分.也是我们为了改进前一篇博文中的K-Means会因为异常点而产生较大的影响波动.而离群点的检测方法又是多种多样的.除了我会在本篇文中分享的基于密度的离群点检测方法-LOF方法外.还有许多的方法.在这里归纳一些其他的离群点检测的类别.
1. 基于统计分布的离群点检测方法
基于先假设数据集符合如(泊松分布/高斯分布)的模型.将偏离统计规律严重的点筛出.
2. 基于距离的离群点检测方法
这是最早运用于离群点检测的方法.具体原理是,先要指定参数p-数据个数/d-阈值距离.在数据集中,若有一个点它离p个点的距离都大于d,那么就视这个点是一个离群点.
3. 基于偏差的离群点检测方法
把偏离集中区域远的点作为离群点.
4. 基于深度的离群点检测方法
基于随着深度(维度)的加深找到确定为离群点的数据.
5. 基于聚类的离群点检测方法
经过改进,现在的聚类算法可以将那些不严格属于任何一个簇的数据定义为离群的点.

基于「LOF算法」的离群点检测方法

在上文中,提到过在K-Means聚类中,由于是均值聚类.采用的是欧几里德距离,故离群的数据点在样本集不是很丰富的情况下会对最终的聚类结果产生比较大的影响.但是离群值往往有比较有意思的特性值得我们去分析.所以我们一般先将所有的离群值先在聚类前剔除作单独分析.离群的点在我们视觉上可能会有很明显的感觉,比如下图中的红色点在我们看来就是离群的点

我们要做的K-Means前的预处理就是筛掉这些红色的点.那么具体的处理方法我们就要用到LOF算法了.接下来我们就来看一下LOF算法.

LOF算法

LOF算法全名是局部异常因子算法,Local Outlier Factor(LOF).异常检测的方法多是基于距离来判定的.基于距离的判别方法,较为适用于二维或高维坐标体系内异常点的判别.LOF也是基于距离来判定异常的因子的.还有的是基于分布来判定的,这里稍微的介绍一下.如下图:

上图中为分布判别方法.我们一般把右侧斜线部分就视为是异常的存在.然后回到LOF.我们要实现的是如下图这样的情况.

我们可以发现这里分为了两个簇,左下角的簇密度明显要高于右上角.而我们所用的LOF算法要实现的就是怎么样从密度情况不相同的这两个簇识别出对于它们两者而言的离群点

LOF算法定义

1. k−distance(p),简称dk(p):点p的第k距离
2. d(p,x):两点p和x之间的距离
3. Nk(p):第k距离邻域
4. Reach-dist (p,x):可达距离
5. lrdk(p):局部可达密度
6. LOFk(p):局部离群因子

那么我们一起来看看它们之间的关系以及它们对于我们要计算的离群值有什么贡献.
1.k−distance(p),简称dk(p):点p的第k距离
如下图所示,简单的来说就是离p第k远的点

图中的黑点就是离p点(红色的圆心)第6远的点.箭头所表示的长度即为6-distance(p)即d6(p)

2.d(p,x):这个就是最简单的两点之间的欧几里得距离.即点p和x两个点之间的距离公式.

3.Nk(p):点p的第k距离邻域.即p的第k距离的以内所有点,包括第k距离由于可能会有多个点到圆心距离相同.因此p的第k邻域点的个数 |Nk(p)|≥k,取>条件如下图所示:

此时圆上d6(p)的点共有3个.所以可知(|Nk(p)| = 8) >6.

4.Reach-distk(p,x):可达距离
Reach-distk(p,x)=max|dk(p),d(p,x)|
我们来结合下图解释下上面的这个公式

在图中,我们用P来替代了O点.所以我们可以得到:O点到点X的第K可达距离为「O的第K距离与O/X间的距离」中较大的那一个距离.离点O最近的K个点,O到它们的可达距离被认为相等为dK(O).原因在于真是距离和dK(O)相比较小.
而我们来看上图.其中的O1到点X的第6可达距为
Reach-dist 6 = max|d6(O1),dI(O1,X)| = d6(O1).
O0到X的第6可达距离为Reach-dist 6 = max|d6(O0),d(O0,X)| = d6(O0).

5.lrdk(p):局部可达密度

这个公式的意思就表示点p的第k邻域内的点到p的平均可达距离的倒数.
定义是是p的邻域点Nk(p)到p的可达距离.而不能反过来说.
lrdk(p)这个值代表的是一个密度,密度越高,我们认为这越可能是同一个簇,相反的来说.密度越低,是离群点的几率就越是高.而这样想.若我们的p和周围邻域点是同一簇的,那么计算得到的可达距离就更加可能是较小dk(p),由于局部可达密度是Reach-dist(p)的倒数,所以p和周围邻域点是同一簇这种情况的密度值较高.如果p和周围邻居点较远,那么可达距离可能都会取较大值d(p,X),平均Reach-dist(p)越大导致局部可达密度较小,所以是离群点的可能性较大.

6.LOFk(p):局部离群因子
计算局部离群因子的公式如下所示:

局部离群因子可以标示数据异常的水平,异常水平的大小表明了数据领域内数据点的孤立水平.
这个公式表示的是点X的邻域点Nk(X)的局部可达密度与点X的局部可达密度之比的平均数
如果这个比值越接近1,说明X和其邻域内点密度差不多,X可能和邻域同属一簇;如果这个比值越小于1,说明X处的密度高于其邻域点密度,X为密集点;如果这个比值越大于1,说明X的密度小于其邻域点密度,X越大越可能是异常的离群点.

LOF算法的优点以及缺点

优点

仅需要设置k的值,比较容易实现;算法由于是基于密度的,所以对X以及周围的K个点都进行了分析,降低了密度极大和密度极小对于整体数据集分析的影响.使结果比较精确.

缺点

若数据集确定了,离群点的确定和K的选取有关.当k选择不同时,离群点会发生改变.所以需要不断的调整参数来使结果符合预期.

LOF算法的实现步骤

算法实现的流程如下所示:
(1)选择合适的K
(2)获得数据集中每一个数据对象的邻域.并且通过对于欧几里德距离的计算出每个数据对象到其领域内所有数据对象点的距离.
(3)利用(1)中的结果,根据文章的上述公式,通过对所有的数据对象进行遍历,推导出所有数据对象的局部离群因子.
(4)通过定义的阈值,我们可以找到那些局部离群因子超过我们所设阈值的数据点并把它们作为离群点.

下面是C#中实现LOF算法的代码

 private void LOFDist() {
//xlxw.ver
LOFk = ; //k
maxLof = ; //阈值 NkLOF = new int[RowCount, LOFk];
lrdk = new double[RowCount];
LOFK = new double[RowCount];
double tmpLofSum = ; for (int i = ; i < RowCount - ; i++) {
Nk(i); //确定数据的领域Nk(p)以及计算出lrdk
}
richTextBox1.Text += "\nLOF计算中";
//计算LOFK
for (int i = ; i < RowCount; i++) {
tmpLofSum = ;
for (int j = ; j < LOFk; j++) {
tmpLofSum += lrdk[NkLOF[i, j]]/ lrdk[i];
}
LOFK[i] = tmpLofSum / LOFk;
}
richTextBox1.Text += "\n分析得到的离群点:";
//LOFK显示在ListView
for (int i = ; i < RowCount - ; i++) {
if (LOFK[i] > maxLof) richTextBox1.Text += "\n第" + (i+).ToString() + "个数据";
XlsDataSh.Items[i].SubItems[].Text = LOFK[i].ToString();
}
} private void Nk(int DataPtS) {
double[] TmpDis = new double[RowCount];
double tmpdis = ,tmpNpKMax = ,tmpSum = ; //计算所有的距离
for (int i = ; i < RowCount - ; i++) {
tmpdis = ;
for (int j = ; j < ; j++) {
tmpdis += Math.Pow((System.Convert.ToDouble(XlsDataSh.Items[i].SubItems[j].Text) - (System.Convert.ToDouble(XlsDataSh.Items[DataPtS].SubItems[j].Text))), );
}
TmpDis[i] = Math.Pow(tmpdis, 1.0/);
} double[] copy = new double[TmpDis.Length];
TmpDis.CopyTo(copy, ); //确定数据的领域Nk(p)
for (int i = ; i < LOFk; i++) {
tmpNpKMax = ;
for (int j = ; (j < RowCount - ); j++) {
if (copy[j] > tmpNpKMax) {
tmpNpKMax = copy[j];
NkLOF[DataPtS, i] = j;
}
}
copy[NkLOF[DataPtS, i]] = ;
} //计算出lrdk
for (int i = ; i < LOFk; i++) {
tmpSum += TmpDis[NkLOF[DataPtS, i]];
}
lrdk[DataPtS] = LOFk / tmpSum; }
}

代码注释:

1. 同上一篇文章一样,这里用到了Excel中的数据集.数据从Excel的Xls文件中导出到了C#控件中的ListView里,这个控件的名字是:XlsDataSh,在程序的代码里可以看到这个控件的名字.
2. 第143个数据点是我作为监督对象设成的全0来检测LOF算法的.
3. 这里的K值(邻域)的设定是20.因为通过上一篇博文,可以看到我设定的分组数是5,所以在一个一百多人的班级我觉得20是比较合适的分组k值.
4. 阈值我设了3.由于正常情况的数据点应该在1的领域范围内.为了凸显异常程度所以我设置的阈值是3.

运行效果图

从图一中我们可以论证我们前面的结论.正常的数据点应该是在1附近的范围内的.从图二的异常点  -  第143号数据点可以看出.它的离群因子为5远大于1也大于我们设置的阈值,所以我们可以得出这一定是一个离群点.

参考

1. 「基于GPU的LOF算法加速」田畔 2014.4.22 论文
2. 「基于模糊聚类分析的数据异常知识发现方法」李建勋 2015.7硕士学位论文
3. 「一种改进的LOF异常点检测算法」周鹏、程艳云 2017.9.27论文网络出版

C#下实现的K-Means优化[1]-「离群点检测」的更多相关文章

  1. 学号20175313 《实现Linux下Sort -t : -k 2功能》第十二周

    目录 一.题目要求 二.题目理解 三.设计思路 四.代码实现 五.代码链接 六.运行结果截图 七.参考资料 一.题目要求 实现Linux下Sort -t : -k 2的功能 二.题目理解 -t 分隔符 ...

  2. 「白帽黑客成长记」Windows提权基本原理(下)

    上一篇文章我们介绍了信息收集方法和WMIC,今天我们将跟随作者深入学习Windows提权基本原理的内容,希望通过这两篇文章的讲解,大家能够真正掌握这个技能. 推荐阅读:「白帽黑客成长记」Windows ...

  3. [转帖]「白帽黑客成长记」Windows提权基本原理(下)

    「白帽黑客成长记」Windows提权基本原理(下) https://www.cnblogs.com/ichunqiu/p/10968674.html 提权.. 之前还在想 为什么 我的 sqlserv ...

  4. VMWare9下基于Ubuntu12.10搭建Hadoop-1.2.1集群

    VMWare9下基于Ubuntu12.10搭建Hadoop-1.2.1集群 下一篇:VMWare9下基于Ubuntu12.10搭建Hadoop-1.2.1集群-整合Zookeeper和Hbase 近期 ...

  5. 【LibreOJ】#6354. 「CodePlus 2018 4 月赛」最短路 异或优化建图+Dijkstra

    [题目]#6354. 「CodePlus 2018 4 月赛」最短路 [题意]给定n个点,m条带权有向边,任意两个点i和j还可以花费(i xor j)*C到达(C是给定的常数),求A到B的最短距离.\ ...

  6. 在linux环境下安装redis并且搭建自己的redis集群

    此文档主要介绍在linux环境下安装redis并且搭建自己的redis集群 搭建环境: ubuntun 16.04 + redis-3.0.6 本文章分为三个部分:redis安装.搭建redis集群 ...

  7. VMWare9下基于Ubuntu12.10搭建Hadoop-1.2.1集群—整合Zookeeper和Hbase

    VMWare9下基于Ubuntu12.10搭建Hadoop-1.2.1集群-整合Zookeeper和Hbase 这篇是接着上一篇hadoop集群搭建进行的.在hadoop-1.2.1基础之上安装zoo ...

  8. docker并不能把部署的工作「减少为0」,比较好的情况下是「基本减少为1」

    很多人说docker改变了运维世界,这句话是从群体角度来说的,是统计学意义上的改变,像mysql,python这样被大规模使用的基础应用,docker化之后为整个群体所节省的时间是非常巨大的. 有人可 ...

  9. Socket的用法——NIO包下SocketChannel的用法 ———————————————— 版权声明:本文为CSDN博主「茶_小哥」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/ycgslh/article/details/79604074

    服务端代码实现如下,其中包括一个静态内部类Handler来作为处理器,处理不同的操作.注意在遍历选择键集合时,没处理完一个操作,要将该请求在集合中移除./*模拟服务端-nio-Socket实现*/pu ...

随机推荐

  1. python练习题,写一个方法 传进去列表和预期的value 求出所有变量得取值可能性(例如list为[1,2,3,4,5,6,12,19],value为20,结果是19+1==20只有一种可能性),要求时间复杂度为O(n)

    题目:(来自光荣之路老师)a+b==valuea+b+c=valuea+b+c+d==valuea+b+c+d+...=valuea和b....取值范围都在0-value写一个方法 传进去列表和预期得 ...

  2. Linux基础命令---unzip

    unzip 解压zip指令压缩过的文件.unzip将列出.测试或从ZIP存档中提取文件,这些文件通常在MS-DOS系统中找到.默认行为(没有选项)是将指定ZIP存档中的所有文件提取到当前目录(及其下面 ...

  3. redis 哨兵机制环境搭建

    Redis哨兵机制,一主二从 注:Redis哨兵切换,建议一主多从 一.一主二从 教程步骤:https://www.cnblogs.com/zwcry/p/9046207.html 二.哨兵配置(se ...

  4. (三)github之GIT的导入

    什么是版本管理? git是一款[分散型版本管理]软件,提供了开发过程中不可少的功能,例如记录一款软件添加或者更改源代码的过程,回溯到特定阶段,恢复误删除的文件等. 集中型:将仓库集中放在服务器中,一旦 ...

  5. kafka调试遇到的问题

    在三台机器上以不同的端口部署了三个kafka和zookeeper实例,对应三套环境. 如: zk1:2181 zk2:2182 zk3:2183 kafka1:9092 kafka2:9093 kaf ...

  6. 如何使用python来对二维数组进行排序

    1.复合排序 直接用numpy的lexsort就可以 import numpy as np data = np.array([[1,2,3,4,5], [1,2,3,6,7], [2,3,4,5,7] ...

  7. Visual Status各个版本官网下载

    网址:https://www.visualstudio.com/zh-hans/vs/older-downloads/

  8. 如何替换vi的配色方案

    答: 1.获取配色方案 git clone git://github.com/altercation/vim-colors-solarized.git ~/.vim/bundle/vim-colors ...

  9. 项目中同一个dll的x86和x64同时引用

    <ItemGroup Condition=" '$(Platform)' == 'x86' "> <Reference Include="System. ...

  10. v-if和v-show区别

    v-if和v-show区别 v-if判断是否要加载,可以减轻服务器压力,按需加载. v-show 利用了css的display,可以提高客户端的流畅度. 看需求使用那个,如果页面上会经常用到,用v-s ...