使用 IQR、Z-score、LOF 和 DBSCAN 进行异常值检测
你在处理异常值吗?哪种方法更适合检测偏斜或正态分布数据的异常值?
无论你是在执行 EDA 之前进行数据清理过程,将数据传递给机器学习模型,还是执行任何统计测试,本文都将帮助你获得许多此类问题的答案以及实际应用。
文章目录
- 什么是Inliers和Outliers?
- 异常值的识别
- 离群值的真实案例
- 四分位间距 (IQR)
- Z 分数法
- 局部异常值查找器 (LOF)
- 用于噪声应用的基于密度的空间聚类 (DBSCAN)
- 结论
什么是Inliers和Outliers?
Outliers(异常值)是看起来与给定数据集中的大多数其他值有很大差异的值**。**异常值通常可能是由于新发明(真正的异常值)、新模式/现象的发展、实验错误、很少发生的事件、异常、由于排版错误导致的错误输入数据、数据记录系统/组件故障等而出现的。
Inliers(正常值)是除异常值之外的分布中的所有数据点。
异常值的识别
全局或点异常值: 偏离分布的单个值/数据点,大多数异常值检测方法通常旨在检测点/全局异常值。
**集合异常值:**当一组数据点偏离分布时,称为集合异常值。根据特定领域来解释它们的相关性是完全主观的。此外,集合异常值表明新现象或发展的形成。
**上下文异常值:**这些是基于对其相关性的解释的特定条件,例如语音识别技术中的单一背景噪声。
图1:点/全局或集体异常值
为了便于理解,我举了一个例子:关于三年内废钢销售的真实案例研究。
离群值的真实案例
考虑到 2018 年至 2022 年在印度各地销售的钢板废品率 (Rs/Kg) 的真实情况,我们已捕获以了解统计数据并预测未来的价格。尽管如此,在此之前,作为数据清理过程的一部分,我们希望了解异常值的存在及其相应的权重。
导入重要库以加载数据集并进行进一步分析:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import scipy.stats as st
%matplotlib inline
import warnings
warnings.filterwarnings('ignore')
df=pdf.read_excel("scrap_data.xlsx", skiprows=2)
df.head(), print('shape of data:',df.shape)
为了了解趋势,我尝试在两个主要的自变量(‘Scrap Rate’ and ‘Scrap Weight’)上绘制线图,并参考其销售日期。
plt.figure(figsize =(15,5))
plt.subplot(1,2,1)
sns.lineplot(x=df['Job Start Date'], y=df['Rate in Rs./Kg.'], color='r') plt.title("Steel Scrap Rate (Rs/Kg)", fontsize=20)
plt.xlabel('Date') plt.subplot(1,2,2)
sns.lineplot(x=df['Job Start Date'], y=df['Scrape Sale Qty.'], color='b') plt.title("Steel Scrap Weight (Rs/Kg)", fontsize=20)
plt.xlabel('Date')
从废品率特征的趋势来看,我们了解到超过 120 Rs/kg 的费率突然飙升,这表明了异常情况的产生,因为一般来说,废品率必须相同并且逐渐增加或减少。但是,就废品重量而言,根据建设项目的规模,在项目结束时产生的废品量随时可能高或低。
让我们尝试应用检测和处理异常值的不同方法。
四分位间距 (IQR)
IQR 通过将数据集分成四个相等的四分位数来测量变异性。首先,将整个数据按升序排序,然后将其分成四个相等的四分位数,分别称为 Q1、Q2、Q3 和 Q4,可以使用以下等式计算。当数据形成偏态分布时,IQR 方法最适合。
第一个四分位数 (Q1) 将最小的 25% 的值与其他 75% 的较大值相除。
Q1 = (n+1)/4 排名值(第 25 个百分位)
第三分位数 (Q3) 将最小的 75% 与最大的 25% 相除。
Q3 = 3(n+1)/4 排名值(第 75 个百分位)
IQR(分位数范围)= Q3– Q1
下限 = Q1 – 1.5 x IQR
上限 = Q3 + 1.5 x IQR
因此,可以将异常值视为给定数据集中大于上限 (Q3+1.5*IQR) 且小于下限 (Q1-1.5*IQR) 的任何值。
让我们绘制箱线图以了解异常值的存在;
plt.figure(figsize=(15,5))
plt.subplot(1,2,1)
sns.boxplot(df['Scrape Sale Qty.'])
plt.xticks(fontsize = (12))
plt.xlabel('Steel-Scrap Weight (in Kgs)')
plt.legend (title="Steel Scrap Weight", fontsize=10, title_fontsize=15)
plt.subplot(1,2,2)
sns.boxplot(df['Rate in Rs./Kg.'])
plt.xlabel('Steel Scrap Rate Rs/kg')
plt.xticks(fontsize =(12));
plt.legend (title="Steel Scrap Rate", fontsize=10, title_fontsize=15);
为了使计算更快,我创建了一个函数来导出四分位数范围 (IQR)、下限和上限,并添加了分别删除它们或用上限值或下限值填充它们的条件。
def identifying_treating_outliers(df,col,remove_or_fill_with_quartile): q1=df[col].quantile(0.25) q3=df[col].quantile(0.75) iqr=q3-q1 lower_fence=q1-1.5*(iqr) upper_fence=q3+1.5*(iqr) print('Lower Fence;', lower_fence) print('Upper Fence:', upper_fence) print('Total number of outliers are left:', df[df[col] upper_fence].shape[0]) if remove_or_fill_with_quartile=="drop": df.drop(df.loc[df[col]<lower_fence].index,inplace=True) df.drop(df.loc[df[col]>upper_fence].index,inplace=True) elif remove_or_fill_with_quartile=="fill": df[col] = np.where(df[col] < lower_fence, lower_fence, df[col]) df[col] = np.where(df[col] > upper_fence, upper_fence, df[col])
将函数应用于 Scrap Rate 和 Scrap Weight 列:
identifying_treating_outliers(df,'Scrape Sale Qty.','drop')
identifying_treating_outliers(df,'Rate in Rs./Kg.','drop')
应用函数前的 DF 形状 : (1001, 5)
应用函数后的 DF 形状 : (925, 5)
在应用 ‘indentifying_treating_outliers’ 函数后绘制箱线图以检查异常值的状态:
plt.figure(figsize=(15,5))
plt.subplot(1,2,1)
sns.boxplot(df['Scrape Sale Qty.'])
plt.xticks(fontsize = (12))
plt.xlabel('Steel-Scrap Weight (in Kgs)')
plt.legend (title="Steel Scrap Weight", fontsize=10, title_fontsize=15)
plt.subplot(1,2,2)
sns.boxplot(df['Rate in Rs./Kg.'])
plt.xlabel('Steel Scrap Rate Rs/kg')
plt.xticks(fontsize =(12));
plt.legend (title="Steel Scrap Rate", fontsize=10, title_fontsize=15);
使用 IQR 方法,我们分别从废品率 (Rate > 34 Rs/kg) 和废品重量 (>1503 kg) 中删除了 15 个数据点和 65 个数据点。删除的观察总数为 76。
Z 分数法
值的 Z 分数是该值与平均值之间的差值除以标准差。如果特定数据点的 Z 分数值小于 -3 或大于 +3,则 Z 分数有助于通过值识别异常值。Z 分数可以在数学上表示为;
x=特定值, μ=平均值, σ=标准偏差
下图表示使用 Z 分数将数据从正态分布转换为标准正态分布,此处给出了参考文献。
在我们的数据集中,我们将对 Zscore 大于 +3 且小于 -3 的异常值应用 Zscore。只需几行代码就可以帮助我们获得 Zscore,我们可以使用分布图(之前和之后)看到差异。
# Applying Zscore in Scrap Rate column defining dataframe by dfn
zr = st.zscore(df['Rate in Rs./Kg.'])
dfn = df[(zr-3)] # Applying Zscore in Steel Weight Column defining dataframe by dfnf
zw= st.zscore(dfn['Scrape Sale Qty.'])
dfnf = dfn[(zw-3)]
plt.figure(figsize=(12,5))
plt.subplot(1,2,1)
sns.distplot(df['Rate in Rs./Kg.'])
plt.title('Z Score Plot Before Removing Outlier',fontsize=15)
plt.subplot(1,2,2)
sns.distplot(st.zscore(dfn['Rate in Rs./Kg.']))
plt.title('Z Score Plot After Removing Outlier',fontsize=15)
我们的数据形成了一个正偏态分布(偏度值 - 0.874),在上述曲线中,该分布不能被视为近似正态分布。对比应用Zscore前后显示的曲线图,可以看到显著的改善。
print('before df shape', df.shape)
print('After df shape for Observation dropped in Scrap Rate', dfn.shape)
print('After df shape for observation dropped in weight', dfnf.shape)
使用 Z Score 方法,在 Scrap Rate 和 Scrap Weight 列中,我们删除了 Zscore -3 的 21 个数据点(3 个来自 Scrap Rate列,18 个来自 Scrap Weight列)。
局部异常值查找器 (LOF)
Local Outlier Finder 是一种无监督机器学习技术,用于根据数据点的最近邻域密度检测异常值,并且在数据集的分布(密度)不同时效果很好。LOF 基本上考虑了 K 距离(点之间的距离)和 K 邻居(点集位于 K 距离(半径)的圆内)。
Lof 考虑了两个主要参数:
(1) n_neighbors:默认值为 20 的邻居数
(2) Contamination:给定数据集中异常值的比例,可以设置为“auto”或浮点值 (0, 0.02 , 0.005)。
导入重要库并定义模型
from sklearn.neighbors import LocalOutlierFactor
d2 = df.values #converting the df into numpy array
lof = LocalOutlierFactor(n_neighbors=20, contamination='auto')
good = lof.fit_predict(d2) == 1
plt.figure(figsize=(10,5))
plt.scatter(d2[good, 1], d2[good, 0], s=2, label="Inliers", color="#4CAF50")
plt.scatter(d2[~good, 1], d2[~good, 0], s=8, label="Outliers", color="#F44336")
plt.title('Outlier Detection using Local Outlier Factor', fontsize=20)
plt.legend (fontsize=15, title_fontsize=15)
在我们的例子中,我将污染设置为“auto”(参见上图)以查看结果,发现 LOF 的性能不佳,因为我的数据传播(密度)没有太大偏差。此外,我尝试了 0.005、0.01、0.02、0.05 和 0.09 的不同污染值,但性能并不是那么好。
用于噪声应用的基于密度的空间聚类 (DBSCAN)
当我们的数据集足够大并且具有多个数字特征(多变量)时,使用 IQR、Zscore 或 LOF 处理异常值变得很困难。在这里,SK-Learn 库 DBSCAN 可以帮助我们处理多变量数据集的异常值。
DBSCAN 考虑两个主要参数(如下所述)与最近的数据点形成一个集群,并根据高密度或低密度区域检测 Inliers 或 outliers。
(1) Epsilon(我们可以根据k-距离图计算的数据点的半径)
(2) Min_samples(Epsilon(半径)中要考虑的数据点数量,取决于领域知识或专家建议)
然而,在我们的例子中,我们没有超过 5 个特征,我们只是从中选择了两个重要的数字特征来应用我们的学习并对其进行可视化。由于目前技术和人脑在完全可视化多维数据方面的限制,我们正在将 DBSCAN 应用于我们的数据集。
导入库并拟合模型。为了消除数据集中的噪声,我们使用 Min-Max Scaler 对数据进行了归一化。
from sklearn.cluster import DBSCAN
from sklearn.preprocessing import MinMaxScaler
mms = MinMaxScaler()
df[['Scrape Sale Qty.','Rate in Rs./Kg.']] = mms.fit_transform(df[['Scrape Sale Qty.','Rate in Rs./Kg.']])
df.head()
from sklearn.neighbors import NearestNeighbors
neigh = NearestNeighbors(n_neighbors=2)
nbrs = neigh.fit(df[['Scrape Sale Qty.', 'Rate in Rs./Kg.']])
distances, indices = nbrs.kneighbors(df[['Rate in Rs./Kg.', 'Rate in Rs./Kg.']])
# Plotting K-distance Graph
distances = np.sort(distances, axis=0)
distances = distances[:,1]
plt.figure(figsize=(8,5))
plt.plot(distances)
plt.title('K-distance Graph',fontsize=20)
plt.xlabel('Data Points sorted by distance',fontsize=14)
plt.ylabel('Epsilon',fontsize=14)
plt.show()
上图显示最大 Epsilon 值接近 0.08,对于样本量(我们希望在每个数据点的 epsilon 值内的点数),我们现在选择 10。
model = DBSCAN(eps = 0.08, min_samples = 10).fit(data)
colors = model.labels_
plt.figure(figsize=(10,7))
plt.scatter(df['Rate in Rs./Kg.'], df['Scrape Sale Qty.'], c = colors)
plt.title('Outliers Detection using DBSCAN',fontsize=20)
DBSCAN 技术使用基于密度的空间聚类有效地检测了显着的异常值,如下图所示。
结论
在这里,我们经历了从数据集中检测异常值的四种方法,在真实世界数据集上找到了它们的实现,并观察了不同的结果。然而,这些方法的应用还取决于数据集的大小、分布和上下文(单变量、双变量或多变量)。所有这些技术都有一定的优点和缺点。
IQR 是最简单和最能用数学解释的技术。单变量和双变量数据可以很好地识别异常值,因为它将中值视为离散值的度量来检测极值,但在处理大量数字特征时仅限于多变量数据集。
在我们的案例中,我们通过定义一个检测和处理异常值的函数来应用它,并将 76 个丢弃的数据点检测为异常值。
Zscore 衡量原始数据与标准差单位中的平均值的距离,并且比其在正态分布数据集中的应用具有优势,但是当数据集不对称(左偏或右偏)时,Zscore 技术可能会导致错误的结果.
我们将其应用于我们的数据集,该数据集似乎略微偏斜,并检测到 21 个数据点作为潜在的异常值。
LOF(局部Ourliter Factor)在数据分布(密度)在整个空间中分布不均匀时具有优势,因为它根据与其他全局方法难以识别的邻近密集区域的接近程度来识别异常值。
然而,可解释性是一个问题,因为很难说在什么阈值下数据点可以被视为异常值。
DBSCAN 不需要定义多个集群,并且能够检测数据分布任意分布且线性不可分的异常。在处理不同密度的数据传播时,它有其自身的局限性。在我们的案例中,它检测到 16 个数据点作为潜在的异常值。
使用 IQR、Z-score、LOF 和 DBSCAN 进行异常值检测相关推荐
- 五种常用的异常值检测方法(均方差、箱形图、DBScan 聚类、孤立森林、Robust Random Cut Forest
什么是异常/离群点? 在统计学中,离群点是并不属于特定族群的数据点,是与其它值相距甚远的异常观测.离群点是一种与其它结构良好的数据不同的观测值. 例如,你可以很清楚地看到这个列表中的离群点:[20,2 ...
- 使用Z标准化得到的阈值判断异常值
有关异常值的确定有很多规则和方法,这里使用Z标准化得到的阈 值作为判断标准:当标准化后的得分超过阈值则为异常.完整代码如 下: import pandas as pd # 导入Pandas库 # 生成 ...
- 五种常用的异常值检测方法(均方差、箱形图、DBScan 聚类、孤立森林、Robust Random Cut Forest)
https://blog.csdn.net/u013328485/article/details/95043012
- python异常值检测
Anomaly Detection异常检测 What are Outliers ? Statistical Methods for Univariate Data Using Gaussian Mix ...
- NEAR:新生儿EEG数据的伪迹去除流程
文章来源于微信公众号(茗创科技),欢迎有兴趣的朋友搜索关注. 导读 EEG对于研究新生儿神经认知功能很有价值.但目前很难记录到高质量的新生儿EEG数据.相较于成人和大一点的婴儿,新生儿注意力持续时间有 ...
- 知物由学 | 行为时序建模在社交引流黑产识别中的应用
社交欺诈问题日益凸显 近年来,陌生人社交软件满足了城市青年拓宽社交圈和找陌生人倾诉的需求,但由于其天然的婚恋交友属性,导致成为色情/广告引流.以及杀猪盘/杀鱼盘/杀鸟盘等欺诈类黑产频繁入侵的重灾区. ...
- Machine Learning for Technical Debt Identification
目录 Abstract: 1 INTRODUCTION 2 RELATED WORK 3 METHODOLOGY 3.1 Data Collection 3.1.1 Project Selection ...
- 消解原理推理_什么是推理统计中的Z检验及其工作原理?
消解原理推理 I Feel: 我觉得: The more you analyze the data the more enlightened, data engineer you will becom ...
- Python数据分析:异常值检验的两种方法 -- Z 分数 上下分位点(放入自写库,一行代码快速实现)
本文已在公众号 " 数据分析与商业实践 " 首发.关注一下~,更多商业数据分析案例源码等你来撩.后台回复 "异常值" ,即可获取本文的案例示范与包含详细注释的源 ...
- Z-score(Z值)的意义--转载
http://blog.sina.com.cn/s/blog_72208a6a0101cdt1.html http://www.docin.com/p-350677620.html http://we ...
最新文章
- LeetCode简单题之杨辉三角
- mybatis的面试一对一,一对多,多对多的mapper.xml配置
- python实现数据库连接池_Python实现Mysql数据库连接池
- python的编程模式-实例讲解Python设计模式编程之工厂方法模式的使用
- 【opencv】15.H265Decoder解码h265为cv::Mat完整代码
- 《中国新说唱》怎么就把小众文化唱凉了
- 博通1300亿美元收购高通,一场充满大饼和落井下石的“大戏”
- linux安卓主线程同步,Android解决:使用多线程和Handler同步更新UI
- SAP UI5 batch 请求的响应解析流程分析
- Vue.js2.0核心思想
- 语言教案 小小计算机,小班《小小手机本领大》语言教案
- 浏览器存储,储存,Cookie,WebStorage,IndexedDB
- 什么是动态链接库(DLL)以及常见问题
- win11虚拟内存如何设置 Windows11设置虚拟内存的步骤方法
- SpringBoot兼容人大金仓数据库
- IP地址详解、无分类编址和路由寻址(计算机网络二)
- 数学专业英语 -- 期望、方差、中心极限定理
- rss opml_分享我的OPML,所有人都在做
- 易语言群控雷电_安卓群控系统雷电模拟器安卓多开模拟器多开群控系统企业自动化的营销系统软件-资源下载随便下源码网...
- [Linq] Linq如何调用外部方法?