找回密码
 会员注册
查看: 23|回复: 0

Python离群点检测算法--LOF详解

[复制链接]

11

主题

0

回帖

34

积分

新手上路

积分
34
发表于 2024-9-9 13:31:12 | 显示全部楼层 |阅读模式
局部离群因子(LOF)是一种有效的无监督学习方法,它使用最近邻搜索来识别异常点,是一种基于密度的技术。在本章中,我将解释其动机和算法,并带领大家在PyOD中进行实践。基于密度的算法都对异常值很敏感,很容易出现过拟合,解决方法是训练多个模型,然后汇总得分。通过聚合多个模型,过拟合的几率会降低,预测精度也会提高。PyOD模块提供了几种汇总结果的方法:平均法(Average)、最大值的最大值法(MOM)、最大值的平均值法(AOM)和平均值的最大值法(MOA)。在文中,我将只演示平均法。离群点可以是全局性的,也可以是局部性的离群点很容易感知,但用数学定义却不容易。相距甚远的数据点就是离群点。一次我在海滩岩石上看日落,一群海鸥站在我旁边的岩石上,有一只灰色的海鸥独自站在另一块岩石上。从我坐的地方看,那只灰色的海鸥是个异类。虽然海滩很长,海滩上还有很多其他的单身海鸥。从海滩的近处向远处看,那只灰色海鸥并不像离群的。上述故事表明,离群点可能是全局离群点,也可能是局部离群点。数据点远离其附近的数据体时,会被视为离群值。图(A)展示了局部异常值和全局异常值。全局的算法可能只能捕捉到全局离群值。如果需要识别局部异常值,就需要一种能够关注局部邻域的算法。局部邻域中数据点的密度是关键,而LOF将不同密度的局部邻域纳入了识别局部离群值的考虑范围。全局和局部离群值LOF如何工作?LOF计算的是数据点相对于其相邻数据点的密度偏差,用于识别离群点。下图中a1点的密度远低于蓝色簇的点,显示蓝色聚类比绿色聚类更密集。当数据密度不同,LOF尤其有效。点a2是绿色聚类的局部离群点。LOF可以检测局部离群点。局部离群因子(LOF)旨在调整不同局部密度的变化。它分为五个步骤,其中第四步涉及局部密度,第五步比较点的邻域密度与附近数据集群的密度。Step1:K-neighborsStep2:K-distanceStep3:Reachability-distance(RD)Step4ocalreachabilitydensity(LRD)Step5ocalOutlierFactorofK-neighborOF(k)Reachability-distance首先,K-近邻是指K-近邻之前的圆周区域。在图(B)中,O点的第一、第二和第三近邻分别是p1、p2和p3。虚线圆是K=3时K最近邻的面积。这一定义与KNN相同。其次,K-distance(o)是点O到K最近邻居的距离。该距离可以用欧氏距离或曼哈顿距离测量。第三,点O的可达性距离是K-distance*(o*)或任意点P与O之间距离的最大值。P2到O的距离为d(P2,O),小于点P3到O的距离,即K-distance(o)。因此P2的RD为K-distance(o),即P3到O的距离。步骤1和2只是帮助定义步骤3中的可达性距离。可及距离公式是为了减少所有靠近O点的点P的*d(p,o)*的统计波动。在步骤4中,LRD是O点与其邻居的平均可达距离的倒数。LRD值低意味着最近的数据体远离O点。最后,在步骤5中,LOF是点O的K个邻居的平均LRD与其LRD之比,如下式所示。第一项是K个邻居的平均LRD。LOF是p的LRD与点p的K个近邻的LRD之比的平均值。第二项是点O的LRD。如果O点不是离群点,则邻近点的平均LRD与O点的LRD大致相等,此时LOF几乎等于1。另一方面,如果O点是一个离群点,则第一期的邻居平均LRD将高于第二期,此时LOF将大于1。在LOF中使用距离比可以确保考虑到不同的局部密度。无论聚类密度如何,聚类中数据点的LOF值通常都接近于1。例如,在图(A)中,蓝色或绿色聚类中数据点的LOF值都接近1,尽管这两个聚类的密度不同。一般来说,如果LOF>1,则被视为离群点。该数据点与相邻数据点的距离比预期的要远。另一方面,如果一个数据点位于数据密集区域,它就不是离群点。它的LOF值将接近1。建模流程可以通过选择一个阈值来区分离群点得分高的异常观测值和正常观测值。如果先验知识表明异常值的百分比不应超过1%,那么您可以选择一个相应的阈值。对于模型的合理性,两组之间特征的描述统计数据(比如均值和标准差)非常关键。如果预期异常组的某一特征平均值应该高于正常组,而结果恰恰相反,就需要对该特征进行调查、修改或放弃,并重新建模。第一步:建立LOF模型我将使用PyOD的generate_data()函数生成百分之十的离群值。数据生成过程(DGP)将创建六个变量,并且模拟数据集中包含目标变量Y,但无监督模型只使用X变量。目的是为了增加案例的趣味性,异常值的百分比设置为5%,“contamination=0.05”。importnumpyasnpimportpandasaspdimportmatplotlib.pyplotaspltfrompyod.utils.dataimportgenerate_datacontamination=0.05#percentageofoutliersn_train=500#numberoftrainingpointsn_test=500#numberoftestingpointsn_features=6#numberoffeaturesX_train,X_test,y_train,y_test=generate_data(n_train=n_train,n_test=n_test,n_features=n_features,contamination=contamination,random_state=123)X_train_pd=pd.DataFrame(X_train)X_train_pd.head()1234567891011121314151617前两个变量绘制成散点图。散点图中的黄色点是百分之十的异常值。紫色点为正常观测值。#Plotplt.scatter(X_train_pd[0],X_train_pd[1],c=y_train,alpha=0.8)plt.title('Scatterplot')plt.xlabel('x0')plt.ylabel('x1')plt.show()123456PyOD提供了统一的应用程序接口,使得使用PyOD来建立模型非常容易。接下来,我们声明并拟合模型,然后使用函数decision_functions()来生成训练数据和测试数据的离群值。在这里,参数contamination=0.05表示污染率为5%。污染率是异常值的百分比。通常情况下,我们可能不知道离群值的百分比,因此可以根据先验知识来指定一个值。PyOD将污染率默认为10%。尽管该参数不影响离群值分数的计算,但PyOD使用它来推导离群值的阈值,并应用函数predict()来分配标签(1或0)。我已经创建了一个简短的函数count_stat(),用于显示预测值"1"和"0"的计数。threshold_语法显示了指定污染率的阈值。任何高于阈值的离群值都被视为离群值。frompyod.models.lofimportLOFlof=LOF(contamination=0.05)lof.fit(X_train)#Trainingdatay_train_scores=lof.decision_function(X_train)y_train_pred=lof.predict(X_train)#Testdatay_test_scores=lof.decision_function(X_test)y_test_pred=lof.predict(X_test)#outlierlabels(0or1)defcount_stat(vector):#Becauseitis'0'and'1',wecanrunacountstatistic.unique,counts=np.unique(vector,return_counts=True)returndict(zip(unique,counts))print("Thetrainingdata:",count_stat(y_train_pred))print("Thetrainingdata:",count_stat(y_test_pred))#Thresholdforthedefinedcomtanimationrateprint("Thethresholdforthedefinedcomtanimationrate:",lof.threshold_)Thetrainingdata:{0:477,1:23}Thetrainingdata:{0:472,1:28}Thethresholdforthedefinedcomtanimationrate:1.321258785666126lof.get_params(){'algorithm':'auto','contamination':0.05,'leaf_size':30,'metric':'minkowski','metric_params':None,'n_jobs':1,'n_neighbors':20,'novelty':True,'p':2}123456789101112131415161718192021222324252627282930313233343536第2步–为LOF模型确定一个合理的阈值PyOD内置了一个名为threshold_的函数,可根据污染率计算训练数据的阈值。默认情况下,污染率为0.10,因此训练数据的阈值为1.2311。这意味着任何异常值大于1.2311的观测值都会被视为离群值。另一种确定阈值的方法是使用PCA离群点得分的直方图。我们可以根据业务需求来选择阈值。图©展示了得分直方图。我们可以采取更保守的方法,选择一个较高的阈值,这样离群值组中的离群值会更少,但期望更准确。importmatplotlib.pyplotaspltplt.hist(y_train_scores,bins='auto')#argumentsarepassedtonp.histogramplt.title("Histogramwith'auto'bins")plt.xlabel('LOFoutlierscore')plt.show()12345第三步–展示LOF模型正常组和异常组的汇总统计量在第1章中提到了两组特征之间的描述性统计数据(如均值和标准差)对于证明模型的合理性非常重要。我创造了一个名为descriptive_stat_threshold()的简短函数,用于展示基于阈值的正常组和离群组特征的大小和描述性统计。我将阈值简单地设置为5%。您可以尝试不同的阈值来确定离群值组的合理大小。threshold=lof.threshold_#Orothervaluefromtheabovehistogramdefdescriptive_stat_threshold(df,pred_score,threshold):#Let'sseehowmany'0'sand'1's.df=pd.DataFrame(df)df['Anomaly_Score']=pred_scoredf['Group']=np.where(df['Anomaly_Score']1.07),分数不需要过多解释。从统计特征来看,离群组的特征均值小于正常组。离群组中特征的均值高低取决于业务应用,但重要的是,所有均值都应与领域知识保持一致。我们可以利用y_test数据生成混淆矩阵来评估模型性能,该模型表现出色,成功识别了全部25个异常值。Actual_pred=pd.DataFrame({'Actual':y_test,'Anomaly_Score':y_test_scores})Actual_pred['Pred']=np.where(Actual_pred['Anomaly_Score']1时,被视为离群点,即数据点与邻居的距离比预期的要远。另一方面,如果一个数据点位于数据密集区域,则它的LOF值将接近1。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2025-1-10 06:07 , Processed in 0.474466 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表