基于距离的离群点检测算法
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
基于距离的离群点检测算法
08计算机二班侯宇铭张国勇易小倩一、概述:
这个算法是一个基于距离的异常点检测算法,算法以欧式距离为衡量标准,整个算法分三个部分。第四部分的改进是用了类似密度检测的思想,比较了之前步骤选出的怀疑离群点的三近邻,经过C++语言的实现,效果还不错。但是程序稍有漏洞,因此没有在这里体现。但是第四阶段算法的思想已经附在算法描述后面。
本文档附上测试的数据集的arff格式,excel格式,以及txt供程序使用的格式。三种格式的数据都是一样的。数据分布如下:
附上算法涉及的变量名称对应表:
二、算法描述:
(这里以数据集为两个相对集中的数据簇和若干离群点为例进行说明)
第一部分:找出两个质心
Step1: 遍历数据,将数据存入数组dot中该数据设为二维数据,有x,y两个属性。
Step2:设定遍历时的第一个和第二个数据为初始质心。设定两个变量longest_distance分别记录两个初始簇的最长的距离,设置dotcore1变量记录第一个簇的质心,dotcore2变量记录第二个簇的质心。
Step3:循环:当一个新的点p进入程序时,首先比较点p分别到点dotcore1的距离和到dotcore2的距离,选择距离较小的质心(这里假设选择了dotcore1),记该距离为distancep。比较distancep和第一个簇(因为选择了dotcore1)的longest_distance。若distancep
算法流程图:
进入阶段2
图.1 阶段1
第二部分:将所有的点归簇,并筛选一部分点
Step4: 开始第二次点的扫描:当一个新的点p进入程序时,首先比较点p分别到点dotcore1的距离和到dotcore2的距离,选择距离较小的质心。设置点数分簇记录:簇1的点数记录在变量dot_Dispatch1中,簇2的点数记录在变量dot_Dispatch0中。(假设选择了点dotcore1)则点p的序号记录在簇1的数组中。表示点p属于这个簇。若选择了dotcore2,以此类推。同时计算两个簇各个点分别到质心的距离的和。
Step5:在完成了分簇之后,我们对比各个点到质心的距离,若该点的距离大于当前的平均距离,那么将该点分别存入Suspt1和Suspt0数组中,以备以后的过程使用。
第三部分:将怀疑点到质心距离与距离均值的差,再与均值的方差作比较。
Step6: 分别求出两个簇的标准差variance1和variance0。
Step7: 将Suspt1中的各个点的距离减去距离的均值(先以怀疑点p1为例,其他点的处理办法一样),将p1与距离的差值与variance1*1.67(取置信区间为90%)相比较。若p1计算的差值大于variance1*1.67,则将其归入Suspt21和Suspt20数组中,以备以后过程进一步使用。
第一阶段
进入第三阶段
图.2 第二阶段
图.3 第三阶段
(改进设想)第四部分:将Suspt21和Suspt20中的点比较其三近邻,做最终的筛选
Step8: 将Suspt21和Suspt20中的点,(以p1点为例)p1计算与所有的点的距离,取距离值最小的三个,将这三个距离取平均值,得到均值p1avg。求p1avg与所属簇的平均距离的差值,再用这个差值与该簇的标准差*1.67相比,若大于,则确认为离群点。
三、程序实现代码(C++语言)
一、第一阶段:
//录入数据集
//第一步开始:
ifstream ifile ("test1.txt");
if (! ifile)
{ cout << "Error opening file";return 1; }
int i=0;
while(!ifile.eof())
{
ifile>>buffer[dotnum];
// cout< dotnum++; } ifile.close(); int l=0; for(int j=0;j { for(int k=0;k<2;k++) { dot[j][k%2]=buffer[l++]; if(j<=1) dot_Core[j][k%2]=dot[j][k%2]; //把数据第一第二个点设为原始质心 } } /* for (int j=0;j for (int k=0;k<=1;k++) cout< }*/ 文件需是txt格式且坐标xy间用制表符分割;经过这一步录入后dot[j][0]为j点的x坐标,dot[j][0]为j点的Y坐标。 计算出质心: //第一次正序扫描 for(int j=0;j if(distance(j,0) if(distance(j,0)>distance_Longest[0]){ distance_Longest[0]=distance(j,0); dot_Core[0][0]=dot[j][0]; }; } else{ if(distance(j,1)>distance_Longest[1]){ distance_Longest[1]=distance(j,1); dot_Core[1][0]=dot[j][0]; dot_Core[1][1]=dot[j][1]; }; } if(j==dotnum/6) { dot_Core2[0][0]=dot_Core[0][0]; dot_Core2[0][1]=dot_Core[0][1]; dot_Core2[1][0]=dot_Core[1][0]; dot_Core2[1][1]=dot_Core[1][1]; } if(j==dotnum/3) { dot_Core4[0][0]=dot_Core[0][0]; dot_Core4[0][1]=dot_Core[0][1]; dot_Core4[1][0]=dot_Core[1][0]; dot_Core4[1][1]=dot_Core[1][1]; } } dot_Core[0][0]=((dot_Core[0][0]+dot_Core2[0][0])/2+dot_Core4[0][0])/2; dot_Core[0][1]=((dot_Core[0][1]+dot_Core2[0][1])/2+dot_Core4[0][1])/2; dot_Core[1][0]=((dot_Core[1][0]+dot_Core2[1][0])/2+dot_Core4[1][0])/2; dot_Core[1][1]=((dot_Core[1][1]+dot_Core2[1][1])/2+dot_Core4[1][1])/2; //第二次倒序扫描 for(int j=dotnum/2-1;j>=0;j--){ if(distance(j,0) if(distance(j,0)>distance_Longest2[0]){ distance_Longest2[0]=distance(j,0); dot_Core3[0][0]=dot[j][0]; dot_Core3[0][1]=dot[j][1]; }; } else{ if(distance(j,1)>distance_Longest2[1]){ distance_Longest2[1]=distance(j,1);