【机器学习 | 数据挖掘】离群点检测
【作者主页】Francek Chen
【专栏介绍】 ⌈ ⌈ ⌈智能大数据分析 ⌋ ⌋ ⌋ 智能大数据分析是指利用先进的技术和算法对大规模数据进行深入分析和挖掘,以提取有价值的信息和洞察。它结合了大数据技术、人工智能(AI)、机器学习(ML)和数据挖掘等多种方法,旨在通过自动化的方式分析复杂数据集,发现潜在的价值和关联性,实现数据的自动化处理和分析,从而支持决策和优化业务流程。与传统的人工分析相比,智能大数据分析具有自动化、深度挖掘、实时性和可视化等特点。智能大数据分析广泛应用于各个领域,包括金融服务、医疗健康、零售、市场营销等,帮助企业做出更为精准的决策,提升竞争力。
【GitCode】专栏资源保存在我的GitCode仓库:https://gitcode.com/Morse_Chen/Intelligent_bigdata_analysis。
文章目录
- 一、离群点检测的概述
- 二、离群点检测的方法
- 三、基于模型的离群点检测方法
- (一)一元正态分布中的的离群点检测
- (二)混合模型的离群点检测
- 四、基于聚类的离群点检测方法
- (一)丢弃远离其他簇的小簇
- (二)基于原型的聚类
- 五、Sklearn中的异常值检测方法
- 小结
一、离群点检测的概述
就餐饮企业而言,经常会碰到这样的问题:如何根据客户的消费记录检测是否为异常刷卡消费?如何检测是否有异常订单?这一类异常问题可以通过离群点检测解决。
离群点检测是数据挖掘中重要的一部分,它的任务是发现与大部分其他对象显著不同的对象。大部分数据挖掘方法都将这种差异信息视为噪声而丢弃,然而在一些应用中,罕见的数据可能蕴含着更大的研究价值。
因为离群点的属性值明显偏离期望的或常见的属性值,所以离群点检测也称偏差检测。
离群点检测已经被广泛应用于电信和信用卡的诈骗检测、贷款审批、电子商务中、网络入侵、天气预报等领域,如可以利用离群点检测分析运动员的统计数据,以发现异常的运动员。
离群点的概念:离群点(Outlier)是指显著偏离一般水平的观测对象。离群点检测(或称异常检测)是找出不同于预期对象行为的过程。离群点的本质仍然是数据对象,但它与其他对象又显著差异,又被称为异常值。离群点不同于噪声数据。噪声是指被观测数据的随机误差或方差,观测值是真实数据与噪声的混合。而离群点属于观测值,既可能是真实数据产生,也有可能由噪声带来。
离群点的主要成因有:数据来源于不同的类、自然变异、数据测量和收集误差等。主要分为以下两类。
- 第一类离群值是总体固有变异性的极端表现,这类离群值与样本中其余观测值属于同一总体。
- 第二类离群值是由于试验条件和试验方法的偶然偏离所产生的结果,或产生于观测、记录、计算中的失误,这类离群值与样本中其余观测值不属于同一总体。
离群点的类型如下表所示。
分类标准 | 分类名称 | 分类描述 |
---|---|---|
从数据范围 | 全局离群点和局部离群点 | 从整体来看,某些对象没有离群特征,但是从局部来看,却显示了一定的离群性。如图:C是全局离群点,D是局部离群点。 |
从数据类型 | 数值型离群点和分类型离群点 | 这是以数据集的属性类型进行划分的。 |
从属性的个数 | 一维离群点和多维离群点 | 一个对象可能有一个或多个属性。 |
离群点检测的挑战:
- 正常对象和离群点的有效建模
- 针对应用的离群点检测
- 在离群点检测中处理噪声
- 可理解性
二、离群点检测的方法
离群点的检测方法很多,每种方法在检测时都会对正常数据对象或离群点作出假设,从所做假设的角度,离群点检测方法可以分为基于统计学的离群点检测、基于近邻的离群点检测、基于密度的离群点检测、基于聚类以及基于分类的离群点检测。
离群点检测方法 | 方法描述 | 方法评估 |
---|---|---|
基于统计 | 大部分的基于统计的离群点检测方法是构建一个概率分布模型,并计算对象符合该模型的概率,把具有低概率的对象视为离群点。 | 基于统计模型的离群点检测方法的前提是必须知道数据集服从什么分布;对于高维数据,检验效果可能很差。 |
基于邻近度 | 通常可以在数据对象之间定义邻近性度量,把远离大部分点的对象视为离群点。 | 简单,二维或三维的数据可以做散点图观察;大数据集不适用;对参数选择敏感;具有全局阈值,不能处理具有不同密度区域的数据集。 |
基于密度 | 考虑数据集可能存在不同密度区域这一事实,从基于密度的观点分析,离群点是在低密度区域中的对象。一个对象的离群点得分是该对象周围密度的逆。 | 给出了对象是离群点的定量度量,并且即使数据具有不同的区域也能够很好的处理;大数据集不适用;参数选择是困难的。 |
基于聚类 | 一种是利用聚类检测离群点的方法是丢弃远离其他簇的小簇;另一种更系统的方法,首先聚类所有对象,然后评估对象属于簇的程度(离群点得分)。 | 基于聚类技术来发现离群点可能是高度有效的;聚类算法产生的簇的质量对该算法产生的离群点的质量影响非常大。 |
基于分类 | 如果训练数据中有类标号,则可以将其视为分类问题。该问题的解决思路是训练一个可以区分正常数据和离群点的分类模型。 | 构造分类器时,训练数据的分布可能极不均衡,相对正常数据,离群点的数目极少,这样会造成在构建分类器时精度收到很大影响。为了解决两类数据的不均衡问题,可以使用一类模型(One-class Model)进行检测。 |
基于统计模型的离群点检测方法需要满足统计学原理,如果分布已知,则检验可能非常有效。基于邻近度的离群点检测方法比统计学方法更一般、更容易使用,因为确定数据集有意义的邻近度量比确定它的统计分布更容易。基于密度的离群点检测与基于邻近度的离群点检测密切相关,因为密度常用邻近度定义:一种是定义密度为到K个最邻近的平均距离的倒数,如果该距离小,则密度高;另一种是使用DBSCAN聚类算法,一个对象周围的密度等于该对象指定距离d内对象的个数。
三、基于模型的离群点检测方法
通过估计概率分布的参数来建立一个数据模型,如果一个数据对象不能很好地跟该模型拟合,即如果它很可能不服从该分布,则它是一个离群点。
(一)一元正态分布中的的离群点检测
正态分布是统计学中最常用的分布之一。若随机变量 x x x的密度函数 φ ( x ) = 1 2 π e − ( x − μ ) 2 2 σ 2 ( x ∈ R ) \begin{aligned}\varphi(x)=\frac{1}{\sqrt{2\pi}}\mathrm{e}^{-\frac{(x-\mu)^2}{2\sigma^2}}(x∈R)\end{aligned} φ(x)=2π1e−2σ2(x−μ)2(x∈R),则称 x x x服从正态分布 N ( μ , θ ) N(\mu,\theta) N(μ,θ),其中参数 μ \mu μ和 θ \theta θ分别为均值和标准差。
N ( 0 , 1 ) N(0,1) N(0,1)的密度函数如图所示:
N ( 0 , 1 ) N(0,1) N(0,1)的数据对象出现在该分布的两边尾部的机会很小,因此可以用它作为检测数据对象是否是离群点的基础。数据对象落在三倍标准差中心 x x x域之外的概率仅有0.0027。
(二)混合模型的离群点检测
混合是一种特殊的统计模型,它使用若干统计分布对数据建模。每一个分布对应一个簇,而每个分布的参数提供对应簇的描述,通常用中心和发散描述。混合模型将数据看作从不同的概率分布得到的观测值的集合。概率分布可以是任何分布,但是通常是多元正态的,因为这种类型的分布不难理解,容易从数学上进行处理,并且已经证明在许多情况下都能产生好的结果。这种类型的分布可以对椭圆簇建模。
总的讲,混合模型数据产生过程为:给定几个类型相同但参数不同的分布,随机地选取一个分布并由它产生一个对象。
对于混合模型,每个分布描述一个不同的组,即一个不同的簇。通过使用统计方法,可以由数据估计这些分布的参数,从而描述这些分布(簇)。也可以识别哪个对象属于哪个簇。然而,混合模型只是给出具体对象属于特定簇的概率。聚类时,混合模型方法假定数据来自混合概率分布,并且每个簇可以用这些分布之一识别。同样,对于离群点检测,数据用两个分布的混合模型建模,一个分布为正常数据,而另一个为离群点。
聚类和离群点检测的目标都是估计分布的参数,以最大化数据的总似然。一种离群点检测常用的简单的方法:先将所有数据对象放入正常数据集,这时离群点集为空集;再用一个迭代过程将数据对象从正常数据集转移到离群点集,只要该转移能提高数据的总似然。
在某些情况下是很难建立模型的。如:因为数据的统计分布未知或没有训练数据可用。在这种情况下,可以考虑另外其他不需要建立模型的检测方法。
四、基于聚类的离群点检测方法
聚类分析用于发现局部强相关的对象组,而异常检测用来发现不与其他对象强相关的对象。因此聚类分析非常自然地可以用于离群点检测。本节主要介绍两种基于聚类的离群点检测方法。
(一)丢弃远离其他簇的小簇
一种利用聚类检测离群点的方法是丢弃远离其他簇的小簇。通常,该过程可以简化为丢弃小于某个最小阈值的所有簇。这个方法可以和其他任何聚类技术一起使用,但是需要最小簇大小和小簇与其他簇之间距离的阈值。而且这种方案对簇个数的选择高度敏感,使用这个方案很难将离群点得分附加到对象上。
如下图中,聚类簇数K=2,可以直观地看出其中一个包含5个对象的小簇远离大部分对象,可以视为离群点。
(二)基于原型的聚类
另一种更系统的方法,首先聚类所有对象,然后评估对象属于簇的程度(离群点得分)。在这种方法中,可以用对象到它的簇中心的距离来度量属于簇的程度。特别地,如果删除一个对象导致该目标的显著改进,则可将该对象视为离群点。例如,在K均值算法中,删除远离其相关簇中心的对象能够显著地改进该簇的误差平方和(SSE)。
对于基于原型的聚类,评估对象属于簇的程度(离群点得分)主要有两种方法:一是度量对象到簇原型的距离,并用它作为该对象的离群点得分;二是考虑到簇具有不同的密度,可以度量簇到原型的相对距离,相对距离是点到质心的距离与簇中所有点到质心的距离的中位数之比。
如下图,如果选择聚类簇数K=3,则对象A、B、C应分别属于距离它们最近的簇,但相对于簇内的其他对象,这三个点又分别远离各自的簇,所以有理由怀疑对象A、B、C是离群点。
诊断步骤如下:
(1)进行聚类。选择聚类算法(如K-Means算法),将样本集聚为K簇,并找到各簇的质心。
(2)计算各对象到它的最近质心的距离。
(3)计算各对象到它的最近质心的相对距离。
(4)与给定的阈值作比较。
如果某对象距离大于该阈值,就认为该对象是离群点。
基于聚类的离群点检测的改进:离群点对初始聚类的影响:通过聚类检测离群点时,离群点会影响聚类结果。为了处理该问题,可以使用如下方法:对象聚类,删除离群点,对象再次聚类(这个不能保证产生最优结果)。
还有一种更复杂的方法:取一组不能很好的拟合任何簇的特殊对象,这组对象代表潜在的离群点。随着聚类过程的进展,簇在变化。不再强属于任何簇的对象被添加到潜在的离群点集合;而当前在该集合中的对象被测试,如果它现在强属于一个簇,就可以将它从潜在的离群点集合中移除。聚类过程结束时还留在该集合中的点被分类为离群点(这种方法也不能保证产生最优解,甚至不比前面的简单算法好,在使用相对距离计算离群点得分时,这个问题特别严重)。
对象是否被认为是离群点可能依赖于簇的个数(如k很大时的噪声簇)。该问题也没有简单的答案。一种策略是对于不同的簇个数重复该分析。另一种方法是找出大量小簇,其想法是:(1)较小的簇倾向于更加凝聚;(2)如果存在大量小簇时一个对象是离群点,则它多半是一个真正的离群点。不利的一面是一组离群点可能形成小簇从而逃避检测。
利用部分餐饮客户的消费行为特征数据,如下表(对应数据集为consumption_data.xls
),进行聚类分析,并计算各个样本到各自聚类中心的距离,分析离群样本。
Id | R | F | M |
---|---|---|---|
1 | 27 | 6 | 232.61 |
2 | 3 | 5 | 1507.11 |
3 | 4 | 16 | 817.62 |
4 | 3 | 11 | 232.81 |
5 | 14 | 7 | 1913.05 |
6 | 19 | 6 | 220.07 |
7 | 5 | 2 | 615.83 |
8 | 26 | 2 | 1059.66 |
9 | 21 | 9 | 304.82 |
10 | 2 | 21 | 1227.96 |
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 参数初始化
inputfile = '../data/consumption_data.xls' # 销量及其他属性数据
k = 3 # 聚类的类别
threshold = 2 # 离散点阈值
iteration = 500 # 聚类最大循环次数
data = pd.read_excel(inputfile, index_col='Id') # 读取数据
data_zs = 1.0*(data - data.mean())/data.std() # 数据标准化
from sklearn.cluster import KMeans
model = KMeans(n_clusters=k, n_jobs=4, max_iter=iteration) # 分为k类,并发数4
model.fit(data_zs) # 开始聚类
# 标准化数据及其类别
r = pd.concat([data_zs, pd.Series(model.labels_, index=data.index)], axis=1) # 每个样本对应的类别
r.columns = list(data.columns) + ['聚类类别'] # 重命名表头
norm = []
for i in range(k): # 逐一处理
norm_tmp = r[['R', 'F', 'M']][r['聚类类别'] == i] - model.cluster_centers_[i]
norm_tmp = norm_tmp.apply(np.linalg.norm, axis=1) # 求出绝对距离
norm.append(norm_tmp / norm_tmp.median()) # 求相对距离并添加
norm = pd.concat(norm) # 合并
# 设置图形大小,显示网格
plt.figure(figsize=(12, 6)) # 调整图表大小(长宽比可根据需要调整)
# 显示正常点和离群点
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
norm[norm <= threshold].plot(style='go', label='正常点') # 正常点
discrete_points = norm[norm > threshold] # 离群点
discrete_points.plot(style='ro', label='离群点')
# 离群点做标记
for i in range(len(discrete_points)): # 离群点做标记
id = discrete_points.index[i]
n = discrete_points.iloc[i]
plt.annotate('(%s, %0.2f)' % (id, n), xy=(id, n), xytext=(id, n))
# 设置图表标签及标题
plt.xlabel('编号')
plt.ylabel('相对距离')
plt.title('离群点与正常点的相对距离')
plt.grid(True, which='both', linestyle='--', linewidth=0.5) # 显示网格,虚线样式
plt.legend() # 显示图例
plt.savefig('../tmp/离群点与正常点的相对距离图.png', dpi=1080) # 保存图片
plt.show()
得到下面如图所示的距离误差图:
五、Sklearn中的异常值检测方法
sklearn中关于异常检测的方法主要有两种:
(1)novelty detection:当训练数据中没有离群点,我们的目标是用训练好的模型去检测另外新发现的样本;
(2)outlier detection:当训练数据中包含离群点,模型训练时要匹配训练数据的中心样本,忽视训练样本中的其他异常点;
sklearn提供了一些机器学习方法,可用于奇异(Novelty)点或异常(Outlier)点检测,包括OneClassSVM、Isolation Forest、Local Outlier Factor (LOF) 等。其中OneClassSVM可用于Novelty Detection,而后两者可用于Outlier Detection。
下面用OneClassSVM检测奇异点。
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.font_manager
from sklearn import svm
xx, yy = np.meshgrid(np.linspace(-5, 5, 500), np.linspace(-5, 5, 500))
# Generate train data
X = 0.3 * np.random.randn(100, 2)
X_train = np.r_[X + 2, X - 2]
# Generate some regular novel observations
X = 0.3 * np.random.randn(20, 2)
X_test = np.r_[X + 2, X - 2]
# Generate some abnormal novel observations
X_outliers = np.random.uniform(low=-4, high=4, size=(20, 2))
# Fit the model
clf = svm.OneClassSVM(nu=0.1, kernel="rbf", gamma=0.1)
clf.fit(X_train)
# Predictions
y_pred_train = clf.predict(X_train)
y_pred_test = clf.predict(X_test)
y_pred_outliers = clf.predict(X_outliers)
# Count errors
n_error_train = y_pred_train[y_pred_train == -1].size
n_error_test = y_pred_test[y_pred_test == -1].size
n_error_outliers = y_pred_outliers[y_pred_outliers == 1].size
# Plot the decision boundary
Z = clf.decision_function(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.title("Novelty Detection")
plt.contourf(xx, yy, Z, levels=np.linspace(Z.min(), 0, 7), cmap=plt.cm.PuBu)
a = plt.contour(xx, yy, Z, levels=[0], linewidths=2, colors='darkred')
plt.contourf(xx, yy, Z, levels=[0, Z.max()], colors='palevioletred')
# Plot points
b1 = plt.scatter(X_train[:, 0], X_train[:, 1], c='blue', s=40)
b2 = plt.scatter(X_test[:, 0], X_test[:, 1], c='green', s=40)
c = plt.scatter(X_outliers[:, 0], X_outliers[:, 1], c='yellow', s=40)
# Set limits and labels
plt.xlim((-5, 5))
plt.ylim((-5, 5))
plt.xlabel(
"error train: %d/200 ; errors novel regular: %d/40 ; "
"errors novel abnormal: %d/40"
% (n_error_train, n_error_test, n_error_outliers)
)
# Add legend
plt.legend([a.collections[0], b1, b2, c],
["learned frontier", "training observations",
"new regular observations", "new abnormal observations"],
loc="upper left",
prop=matplotlib.font_manager.FontProperties(size=11))
plt.show()
利用EllipticEnvelope实现对离群点的检测,它是sklearn协方差估计中对高斯分布数据集的离群点检测方法,该方法在高维度下的表现效果欠佳。
import numpy as np
from sklearn.covariance import EllipticEnvelope
xx, yy = np.meshgrid(np.linspace(-5, 5, 500), np.linspace(-5, 5, 500))
# 生成训练数据
X = 0.3 * np.random.randn(100, 2)
X_train = np.r_[X+2, X-2]
# 生成新用于测试的数据
X = 0.3 * np.random.randn(10, 2)
X_test = np.r_[X + 2, X - 2]
# 模型拟合
clf = EllipticEnvelope()
clf.fit(X_train)
y_pred_train = clf.predict(X_train)
y_pred_test = clf.predict(X_test)
print ("novelty detection result:\n",y_pred_test)
小结
- 离群点(Outlier)是指显著偏离一般水平的观测对象。
- 离群点不同于噪声数据。
- 离群点一般分为全局离群点、条件离群点和集体离群点。
- 离群点检测方法可以分为基于统计学的离群点检测、基于近邻的离群点检测、基于密度的离群点检测、基于聚类以及基于分类的离群点检测。
- 在基于统计学的离群点检测方法中,假设数据集中的正常数据对象由一个统计模型产生,如果某数据不符合该统计模型,则该数据对象是离群点。
- 基于邻近性的方法假定离群点对象与它最近邻的邻近性显著偏离数据集中其他对象与其近邻之间的邻近性。基于邻近型的离群点检测方法有基于距离的和基于密度的方法。
附:以上文中的数据文件及相关资源下载地址:
链接:https://pan.quark.cn/s/57b2c5724101
提取码:maw1