点击上方关注,All in AI中国
作者——Susan Li
异常检测也称为离群点检测,是一种数据挖掘过程,用于确定数据集中发现的异常类型并确定其出现的详细信息。在当今世界,自动异常检测至关重要,因为数据量太大,手动标记异常值是不现实的。自动异常检测在传感器网络中的应用非常广泛,例如欺诈检测、系统健康监测、故障检测、事件检测系统等。
但我想对酒店房间价格进行异常检测。原因有些自私。
你是否有过这样的经历,比如说,你经常去某个地方出差,而且你总是住在同一家酒店。虽然大部分时间,房价几乎是一样的,但偶尔,相同的酒店,相同的房间类型,房价高得令人无法接受的,你不得不换到另一家酒。我经历了好几次,这让我想到,如果我们能够创建一个模型来自动检测这种价格异常呢?
当然,有些情况下,有些异常只会发生一次,并且我们事先已经知道了,可能在未来几年不会再次发生,例如2019年2月2日至2月4日的亚特兰大荒谬的酒店价格。
在这篇文章中,我将探讨不同的异常检测技术,我们的目标是在无监督学习的情况下搜索酒店房间价格的时间序列中的异常。让我们开始吧!
数据
获取数据非常困难,我能够获得一些但数据并不完美。
我们将使用的数据是Personalize Expedia Hotel Searchesdata集的一部分,可在此处找到(https://www.kaggle.com/c/expedia-personalized-sort/data)。
我们将拆分训练集的子集,csv如下所示:
·选择一个数据点最多的酒店property_id = 104517。
·选择visitor_location_country_id = 219,正如我们所知,国家ID 219是美国。我们这样做的原因是统一price_usd列。由于不同国家在展示价格方面有不同的惯例,价值可能是每晚或整个住宿期间。而我们知道,向美国游客展示的价格通常是每晚不含税的。
·选择search_room_count = 1。
·选择我们需要的特性:date_time,price_usd,srch_booking_window,srch_saturday_night_bool。
拆分后后,这是我们将要使用的数据:
此时,我们检测到一个极端异常,即Max price_usd为5584。
如果单个数据实例可以被视为是相对于其他数据数异常的,我们称之为Point Anomalies(例如,以较高的成交价格购买)。我们可以回去检查日志,看看它是什么。经过一番调查后,我猜这可能是一个错误或者用户偶然搜索了一个总统套房但没有预订。为了找到更多不是极端的异常值,我决定删除它。
在这一点上,我相信你已经发现我们遗漏了一些东西,也就是说,我们不知道用户搜索的房间类型,标准房间的价格可能与海景大床房的价格有很大差异。记住这一点,但为了示范目的,我们必须继续。
时间序列可视化
一般来说,非周六晚上的搜索价格会更稳定、更低。周六晚上的搜索价格会上涨。似乎这家酒店在周末很受欢迎。
基于聚类的异常检测
K-均值算法
K-均值算法是一种应用广泛的聚类算法。它创建了"k"个类似的数据点集群。不属于这些组的数据实例可能会被标记为异常。在我们开始K-均值算法聚类之前,我们使用elbow方法来确定最佳聚类数。
从上面的曲线图中,我们看到图形在10个聚类之后趋于平稳,这意味着添加更多聚类并不能解释我们相关变量中的更多方差;在本例中是price_usd。
我们设置n_clusters = 10,并在生成k-均值算法输出时使用数据绘制3D聚类。
现在我们需要找出要保留的组件(特性)的数量。
我们看到第一个组件解释了近50%的差异。第二个组件解释了超过30%的原因。但是,我们必须注意到,几乎没有任何组件是可以忽略不计的。前两个组件包含80%以上的信息。所以,我们将设置n_components = 2。
基于聚类的异常检测中的最重要假设是,如果我们对数据进行聚类,则正常数据将属于聚类,而异常将不属于任何聚类或属于小聚类。我们使用以下步骤来查找和可视化异常。
·计算每个点与其最近质心之间的距离。最大的距离被认为是异常的。
·我们使用outliers_fraction为算法提供有关数据集中存在的异常值比例的信息。情况可能因数据集而异。然而,作为一个起始图,我估计outliers_fraction = 0.01,因为它是在标准正态分布中,Z值得分与Z均值之间的绝对值3的观察值的百分比。
- 使用 outliers_fraction 计算number_of_outliers
- 将阈值设置为这些异常值的最小距离。
- 包含异常的结果1包含上述方法聚类(0:正常,1:异常)。
- 使用群集视图可视化异常。
- 使用时间序列视图可视化异常。
似乎通过k-均值聚类检测到的异常是一些非常高的速率或一些非常低的速率。
用于异常检测的隔离森林
隔离森林(https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.IsolationForest.html)检测异常纯粹基于异常是少数和不同的数据点的事实,在不采用任何距离或密度测量的情况下实现异常隔离。该方法与基于聚类或基于距离的算法有本质区别。
·当应用IsolationForest(https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.IsolationForest.html)模型时,我们设置pollution= outliers_fraction,即告诉模型数据集中异常值的比例为0.01。
·fit和predict(data)对数据执行异常检测,并返回1表示正常,-1表示异常。
·最后,我们使用时间序列视图可视化异常。
支持向量机的异常检测
支持向量机(https://en.wikipedia.org/wiki/Support-vector_machine)通常与监督学习相关联,但是OneClassSVM可用于将异常识别为学习异常检测决策函数的无监督问题:将新数据分类为与训练集相似或不同的数据。
OneClassSVM
根据论文:支持向量法进行新颖性检测(http://users.cecs.anu.edu.au/~williams/papers/P126.pdf)。 SVM是最大边际方法,即它们不建立概率分布模型。SVM用于异常检测的想法是找到对于具有高密度点的区域为正,对于小密度的负区域为负。
- 在拟合OneClassSVM模型时,我们设置nu = outliers_fraction,它是训练误差分数的上限和支持向量分数的下限,并且必须在0和1之间。基本上这意味着我们在数据中期望的异常值的比例。
- 指定要在算法中使用的内核类型:rbf。这将使SVM能够使用非线性函数将超空间投影到更高维度。
- gamma是RBF内核类型的一个参数,并控制各个训练样本的影响——这会影响模型的"平滑度"。通过实验,我没有发现任何显著的差异。
- predict(data)对数据进行分类,因为我们的模型是一个单类模型,返回+1或-1,-1是异常,1是正常。
利用高斯分布进行异常检测
高斯分布也称为正态分布。我们将使用高斯分布来开发异常检测算法,也就是说,我们假设我们的数据是正态分布的。这是一个不能适用于所有数据集的假设,但是当它成立时,它证明了一种有效的方法来发现异常值。
Scikit-Learn的协方差EllipticEnvelope是一个函数,它试图通过假设我们的整个数据是基础多元高斯分布的表达来计算出我们数据的一般分布的关键参数。过程如下:
- 根据之前定义的类别创建两个不同的数据集 ——search_Sat_night,Search_Non_Sat_night。
- 在每个类别上应用EllipticEnvelope(高斯分布)。
- 我们设置pollution参数,即我们数据集中存在的异常值的比例。
- 我们使用decision_function来计算给定观测值的决策函数。它等于移动的马哈拉诺比斯距离。异常值的阈值为0,这确保了与其他异常值检测算法的兼容性。
- 预测(X_train)根据拟合模型预测X_train的标签(1正常,-1异常)。
有趣的是,以这种方式检测到的异常只能观察到异常高的价格,而不是异常低的价格。
到目前为止,我们已经用四种不同的方法进行了价格异常检测。 因为我们的异常检测是无监督学习。在构建模型之后,我们不知道它做得多好,因为我们没有任何东西可以对它进行测试。因此,在将这些方法置于关键路径之前,需要在现场测试这些方法的结果。
Jupyter笔记本可以在Github上找到(https://github.com/susanli2016/Machine-Learning-with-Python/blob/master/Time%20Series%20of%20Price%20Anomaly%20Detection%20Expedia.ipynb)。