当前位置: 首页 > 科技观察

机器学习:基于密度的异常值检测算法

时间:2023-03-18 23:42:39 科技观察

异常值检测(也称为异常检测)是机器学习中查找行为与预期行为非常不同的数据对象的过程。这些对象称为离群值或异常值。最有趣的对象是那些与普通对象明显不同的对象。离群值不是由与其他数据相同的机制生成的。异常检测在许多应用中都很重要,例如:金融数据欺诈通信网络入侵假新闻和错误信息医疗分析工业损害检测安全和监视等。异常值检测和聚类分析是两个高度相关的任务。聚类在机器学习数据集中找到多数模式并相应地组织数据,而离群值检测则试图捕捉那些与多数模式有显着差异的异常。在本文中,我将介绍离群点检测的基本方法,重点介绍一类基于邻近度的算法方法。我还将提供LOF算法的代码实现。异常值和噪声数据首先在机器学习中,您需要区分异常值和噪声数据。应用异常值检测时应去除噪声。它可以扭曲正常对象并模糊正常对象和异常值之间的区别。它可能有助于隐藏异常值并降低异常值检测的有效性。例如,如果用户考虑购买他过去经常购买的更昂贵的午餐,则应将此行为视为“噪声交易”,例如“随机错误”或“方差”。异常值的类型一般来说,异常值可以分为三类,即全局异常值、上下文(或条件)异常值和集体异常值。全局异常值-显着偏离机器学习数据集其余部分的对象数量上下文异常值-显着偏离所选上下文的对象。例如,28?C是莫斯科冬季的异常值,但在其他情况下则不是,28?C不是莫斯科夏季的异常值。聚合离群值——即使单个数据对象可能不是离群值,数据对象的子集也可能与整个机器学习数据集存在显着差异。例如,一小部分人在短时间内大量交易同一只股票,可以认为是操纵市场的证据。EnsembleOutliers通常,一个数据集可以包含不同类型的异常值,并且可以同时属于不止一种类型的异常值。离群点检测方法许多离群点检测方法都包含在文献中并在实践中使用。首先,离群点检测方法是基于用于分析的数据样本是否与领域专家提供的标签一起给出,可以用来建立离群点检测模型。其次,可以根据关于正常对象与异常值的假设将方法分为几组。如果可以使用专家标记的正常和/或异常对象示例,则可以使用它们来构建异常值检测模型。使用的方法可以分为监督方法、半监督方法和无监督方法。监督方法我们将异常值检测建模为分类问题。由领域专家检查的样本用于训练和测试。挑战:阶级失衡。也就是说,离群点的数量通常远小于正常对象的数量。可以使用处理不平衡类的方法,例如过采样。Catchasmanyoutliersaspossible,即recall比accuracy更重要(即不要将正常对象误标记为异常值)因此,必须使用无监督学习方法。无监督异常值检测方法隐含假设正常对象以某种方式“聚集”。换句话说,无监督异常值检测方法期望正常对象比异常值更频繁地遵循模式。挑战:普通对象可能没有任何强模式,但聚合离群点可能在小区域具有高相似性如果正常活动多样且不属于高质量聚类,无监督方法可能具有高误报率并且可能留下许多真正的离群点不受影响。最先进的无监督方法开发了智能想法,无需明确检测集群即可直接解决异常值。半监督方法在许多应用中,虽然可以获得一些带标签的例子是可行的,但这种带标签的例子的数量通常很少。如果一些标记的常见对象可用:使用标记的示例和相邻的未标记对象训练常见对象的模型那些不适合常见对象模型的对象被检测为异常值标记的异常值可能无法很好地覆盖可能的异常值。统计方法统计方法(也称为基于模型的方法)假设正常数据遵循某种统计模型(随机模型)。这个想法是学习适合给定数据集的生成模型,然后将模型低概率区域中的对象识别为异常值。参数化方法参数化方法假设正态数据对象是通过具有参数θ的参数化分布生成的。参数分布f(x,θ)的概率密度函数给出了通过该分布生成对象x的概率。值越小,x越有可能是异常值。正常对象出现在随机模型的高概率区域,而低概率区域的对象是异常值。统计方法的有效性在很大程度上取决于分布假设。例如,考虑具有正态分布的单变量数据。我们将使用最大似然来检测异常值。用于估计参数μ和σ的最大似然法采用μ和σ2的导数并求解生成的一阶条件系统导致以下μ和σ2的最大似然估计参见以下Python示例:importnumpyasnpavg_temp=np。array([24.0,28.9,28.9,29.0,29.1,29.1,29.2,29.2,29.3,29.4])mean=avg_temp.mean()std=avg_temp.std()sigma=std^2print(mean,std,sigma)//28.611.544312144612.3849偏差最大的值为24?,与均值相差4.61。我们知道,在正态分布假设下,μ+/-3σ区域包含了97%的数据。由于4.61/1.54>3,我们认为24???是异常值。我们还可以使用另一种称为Gribbs检验的统计方法来计算z-score。s-标准差但是我们很少处理只有一个属性的数据。涉及两个或多个属性的数据称为多变量。这些方法的核心思想是将多变量数据转化为单变量异常值检测问题。一种流行的方法是2-统计。Oi-O在第i个维度中的值。Ei-所有对象的维度i的平均值,维度n。如果χ2-很大,则该对象是异常值。参数模型的主要缺点是在许多情况下数据分布可能是未知的。例如,如果我们有两个大集合,那么关于正态分布的假设就不会很好地发挥作用。相反,我们假设正态数据对象是由多个正态分布Θ(μ1,σ1)和Θ(μ2,σ2)生成的,并且对于数据集中的每个对象o,我们计算由分布混合生成的概率。Pr(o|Θ1,Θ2)=fΘ1(o)+fΘ2(o)其中fΘ1(o)-Θ1和Θ2的概率密度函数。要学习参数μ和σ,我们可以使用EM算法。非参数方法在异常值检测的非参数方法中,“正常数据”模型是从输入数据中学习的,而不是先验假设的。非参数方法通常对数据做出较少的假设,因此适用于更多场景。例如,我们可以使用直方图。在最简单的方法中,如果一个对象在一个直方图箱中失败,则该对象被认为是正常的。缺点-难以选择垃圾箱尺寸。基于邻近度的算法给定特征空间中的一组对象,可以使用距离度量来量化对象之间的相似性。直观上,与其他物体距离较远的物体可以被视为异常值。基于接近度的方法假设离群对象与其最近邻居的接近度明显偏离该对象与数据集中大多数其他对象的接近度。Proximity-based算法可以分为基于距离的(如果对象没有足够的点,则该对象是异常值)和基于密度的方法(如果对象的密度相对于其邻居低很多,则该对象是异常值)anoutlier)basedondensity距离异常值检测方法是指一个对象的邻域,由给定的半径定义。如果一个对象在其邻域中没有足够的其他点,则该对象被认为是异常值。阈值距离可以定义为对象的合理邻域。对于每个对象,我们可以为该对象找到合理数量的邻居。令r(r>0)为距离阈值,π(0<π<1)为分数阈值。对象o是DB(r,π)dist-距离测量需要O(n2)时间。挖掘基于距离的离群值的算法:基于索引的算法嵌套循环算法基于细胞的算法基于密度的方法基于密度的离群值检测方法研究对象的密度及其邻居的密度。在这里,如果一个对象的密度相对于它的邻居低得多,那么它就是一个异常值。许多现实世界的数据集表现出更复杂的结构,其中对象可能被视为与其本地邻居相关的异常值,而不是与全球数据分布相关的异常值。考虑到上面的例子,基于距离的方法能够检测到o3,但是对于o1和o2,就不是那么明显了。基于密度的思想是我们需要比较一个物体周围的密度与其局部邻居周围的密度。基于密度的异常值检测方法的基本假设是非异常值对象周围的密度与其邻居周围的密度相似,而异常值对象周围的密度与其邻居周围的密度显着不同。dist_k(o)-对象o与其k最近邻之间的距离。o的k距离邻域包含到o的所有距离不大于o的第k个距离dist_k(o)。我们可以用Nk(o)到o的平均距离来衡量o的局部密度,如果o有很近的Neighborhoodo',使得dist(o,o')很小,那么统计波动距离测量值可能非常高。为了克服这个问题,我们可以通过添加平滑效果来切换到以下可达距离测量。k是用户指定的参数,用于控制平滑效果。基本上,k指定要检查以确定对象的局部密度的最小邻域。可达距离是不对称的。对象o的局部可达性密度是我们计算对象的局部可达性密度并将其与其邻居的可比性密度进行比较以量化对象被视为异常值的程度的地方。局部离群因子是o的局部可达密度与o的k最近邻的比值的平均值。o的局部可达密度越低,k的最近邻的局部可达密度越高,LOF值就越高。这恰好捕获了局部密度相对较低的局部异常值。它的k个最近的邻居。LOF算法基于data.csv中的点击流事件频率模式,我们将应用LOF算法计算每个点的LOF,初始设置如下:k=2并使用曼哈顿距离。k=3并使用欧氏距离。结果,我们会发现5个离群值及其LOF_k(o)数据可以从github仓库(https://github.com/zkid18/Machine-Learning-Algorithms)下载,Python实现如下:importpandasapdimportseabornassnsfromscipy。spatial.distanceimportpdist,squareformdata_input=pd.read_csv('../../data/clikstream_data.csv')#Reachdistfunctiondefreachdist(distance_df,observation,index):returndistance_df[observation][index]#LOFalgorithmimplementationfromscratchdefLOF_algorithm(data_input,distance_metric,="pityblock"):distances=pdist(data_input.values,metric=distance_metric)dist_matrix=squareform(distances)distance_df=pd.DataFrame(dist_matrix)k=2ifdistance_metric=="cityblock"else3observations=distance_df.columnslrd_dict={}n_dist_dict={_rayreach_{}forobservationinobservations:dist=distance_df[observation].nsmallest(k+1).iloc[k]indexes=distance_df[distance_df[observation]<=dist].drop(observation).indexn_dist_index[observation]=indexesreach_dist_array=[]forindexinindexe小号:#makeafunctionreachdist(observation,index)dist_between_observation_and_index=reachdist(distance_df,observation,index)dist_index=distance_df[index].nsmallest(k+1).iloc[k]reach_dist=max(dist_index,dist_between_observation_and_index)reach_dist_array.append(reach_dist)lrd_observation=len(索引)/sum(reach_dist_array)reach_array_dict[observation]=reach_dist_arraylrd_dict[observation]=lrd_observation#CalculateLOFLOF_dict={}forobservationinobservations:lrd_array=[]forindexinn_dist_index[observation]:lrd_array.append(lrd_dict[index])LOF=sum(lrd_array)*sum(reach_array_dict[observation])/np.square(len(n_dist_index[observation]))LOF_dict[observation]=LOFreturnsorted(LOF_dict.items(),key=lambdax:x[1],reverse=True)[:p]LOF_algorithm(data_input,p=5)#[(19,11.07),#(525,8.8672286617492091),#(66,5.0267857142857144),#(638,4.3347272196829723),#(177,3.62926333292)6332945、distance_metric='euclidean')#[(638,3.0800716645705695),#(525,3.0103162562616288),#(19,2.8402916620868903),#(66,2.8014102661691211),#(65,2.6456528412196416)]