标签:
在韩家炜书中提到了使用半监督学习方法的异常值检测。在半监督学习中,一部分样本会被标记为“正常”或"离群点“,另一部分样本没有标号,需要算法去估计。貌似这看上去有些像分类得预测问题。但是半监督学习的思想是每次学习后,把最有可能预测正确的样本,加入到下一次迭代的训练集中去。如此不断扩大学习和标记的范围。问题是如何指定一开始的初始标签?( 当然可以人为指定 )
我们来看这个数据集。绿色部分是被标记“正常”的样本。红色的为“异常”的样本。蓝色的为“未标记”样本点。其实这里我自己采用的初始标记方法很简单,就是算出每个样本的K近邻距离的平方和。然后输入两个参数,分别是正常点的默认数量goodSampleNum和异常点的默认数量badSampleNum
这里我默认选goodSampleNum = 10和badSampleNum = 5。至少对这个数据集是合适的。由于我们前面已经算出了每个样本的K近邻距离的平方和,K这里我们取5。所以goodSampleNum对应的正常点应该是K近邻平方和最小的goodSampleNum个。而异常值则是K近邻平方和最大的badSampleNum。具体的代码如下
def genInitLabels( X, k = 3, goodSampleNum = 10, badSampleNum = 5 ): labels = -1 * np.ones( len( X ) ) dists = calKNNSqDists( X, k ) indices = np.argsort( dists ) labels[ indices[ : goodSampleNum ] ] = 0 labels[ indices[ -badSampleNum : ] ] = 1 return labels, dists.reshape(-1,1)
这里的calKNNSqDists就是用来计算每个样本点的K近邻平方和,这里就不展开了。这里会返回初始的label,如果label是-1则为“未标记”
接着就是使用半监督学习方法。我们这里直接调用sklearn里的半监督方法LabelPropagation。这里我们继续使用前面获取的K近邻距离平方和来做为半监督学习方法的输入, 具体代码如下:
def detectOutliers( X, k = 5, goodSampleNum = 10, badSampleNum = 5 ): initLables, dists = genInitLabels( X, k, goodSampleNum, badSampleNum ) semiModel = LabelPropagation( ‘knn‘ , n_neighbors = k + 1 ) semiModel.fit( dists, initLables ) labels = semiModel.predict( dists ) print "Num of outliers:", np.sum( labels == 1 ) return labels, initLables
这里的半监督算法我们依然采用knn核,最近邻由于sklearn里的近邻包含自身,所以就用k + 1。方法获取的结果如下,绿色的为异常值:
大部分的异常点还是找得不错。但是还是有两个点,个人觉得不是太好,离群度不够。无论如何,这篇文章提供了个半监督学习方法在异常值检测应用的思路。
标签:
原文地址:http://www.cnblogs.com/zhuyubei/p/4889311.html