韩家炜的书中提到也可以用基于聚类的方法去做Outlier的识别。的确,outlier这个概念是和cluster这样的场景很相关的。对于工业上的数据来说,一般这个cluster的数量会是1或者2。在找出了cluster后,我们可以发现outlier要么不属于任何的cluster,要么说outlier在这个cluster里显得如此的奇怪。
今天我们用DBSCAN的方法去发现cluster和outleir。DBSCAN的介绍可以见这篇文章: http://www.cnblogs.com/chaosimple/archive/2013/07/01/3164775.html. 文章里也提到了DBSCAN的缺点,也就是说当不同聚类的密度相差明显的时候,这个eps会不起作用。这个问题在我的前一篇文章也提到过。也许基于Shared Nearest Neighbor的方法可以解决这个问题,论文见此 http://www.doc88.com/p-901293142793.html。这个方法以后写到cluster的时候,应该可以分享给大家。
回到今天的主题,基于DBSCAN的聚类方法其实就可以侦测出Noises或者outliers。但是DBSCAN里的eps参数真是让人头疼。这里我们继续采用基于近邻的异常值检测方法一文中提到的estimate_bandwidth方法,这一方法会根据quantile比例的最大近邻距离,估算出整个数据集的平均最大近邻距离。默认这里的quantile是0.3。
整个算法的思路,总结起来就是如前文所述: 如果一个样本,不属于任何一个cluster,则它为outlier。在scikit learn的DBSCAN里, outlier或者noise会被标记为-1。
from sklearn.cluster import DBSCAN, estimate_bandwidth def detectOutliers( X, quantile = 0.3, minPts = 3 ): radius = estimate_bandwidth( X, quantile ) dbscan = DBSCAN( eps = radius, min_samples = minPts ) labels = dbscan.fit_predict( X ) labels = np.array( labels == -1, np.int ) return labels
该方法在同一个数据集的效果如下,和基于近邻的异常检测效果类似.
下次基于聚类的文章会写在cluster之后,每个样本都会属于某个cluster,但是在单个cluster里,outlier会和其余的聚类中样本明显不太一样。