机器学习数据预处理 --- 异常点检测(知识总结&工作随记)
异常检测算法 & PyoD算法库一般情况下,可以把异常检测看成是数据不平衡下的分类问题。但在现实情况中,异常检测问题往往是没有标签的,训练数据中并未标出哪些是异常点,因此必须使用无监督学习。引入PyOD库, 提供20多种异常值检测算法的APIpip install pyod前人经验:(来自zhihu/csdn)1. 不存在普遍意义上的最优模型,不过有些模型的表现一直不错,建议优先考虑。对于
异常检测算法 & PyOD算法库
-
一般情况下,可以把异常检测看成是数据不平衡下的分类问题。但在现实情况中,异常检测问题往往是没有标签的,训练数据中并未标出哪些是异常点,因此必须使用无监督学习。
-
引入PyOD库, 提供20多种异常值检测算法的API
pip install pyod
- 前人经验:(来自zhihu/csdn)
1. 不存在普遍意义上的最优模型,不过有些模型的表现一直不错,建议优先考虑。对于大数据量和高纬度的数据集,Isolation Forest算法的表现比较好。低维度小数据集上,简单算法KNN和MCD的表现不错。
2. LOF类的算法适用于局部区域空间问题,对于完整区域空间,KNN和Iforest更好。
3. KNN每次运行需要遍历所有数据,所以效率比较低,如果效率要求比较高,用聚类方法更好。
4. 对于不同种类的数据,没有哪一种算法是最好的,HBOS算法在某些数据集上的表现非常好,且运算速度很快。
5. ABOD综合效果最差,尽量不要用。
-
KNN & KNN_Average
K近邻距离有3种method设置:
1.距离第k近的点的距离(default)
2.距离最近的k个点的平均距离
3.距离最近的k个点中的中间距离(距离中位数)
-
CBLOF
-
LOF : Local Outlier Factor
通过比较每个点p和其邻域点的密度来判断该点是否为异常点,如果点p的密度越低,越可能被认定是异常点。
密度通过点之间的距离来计算的,点之间距离越远,密度越低,距离越近,密度越高。
-
CBLOF:Cluster-Based Local Outlier Factor (聚类+LOF)
-
-
Feature Bagging
- LOF + 集成学习:默认训练10个LOF作为子检测器,综合输出异常点预测结果(子检测器可以配置成其他基础算法,如KNN、HBOS)
-
Isolation Forest
-
思想:很快划分到叶子节点的大概率是异常
-
算法步骤:
- 从训练数据中随机选择Ψ个点样本点作为subsample,放入树的根节点。
- 随机指定一个维度(attribute),在当前节点数据中随机产生一个切割点p——切割点产生于当前节点数据中指定维度的最大值和最小值之间。
- 以此切割点生成了一个超平面,然后将当前节点数据空间划分为2个子空间:把指定维度里小于p的数据放在当前节点的左孩子,把大于等于p的数据放在当前节点的右孩子。
- 在孩子节点中递归步骤2和3,不断构造新的孩子节点,直到 孩子节点中只有一个数据(无法再继续切割)或 孩子节点已到达限定高度 。
-
预测:
对于一个数据样本x,我们将其传入所有的树中,计算x所处的叶子节点的高度平均值,设置一个阈值,高度不够的视为异常。
-
-
AutoEncoder
- 基于神经网络的算法(基于autoencoder和GAN网络)
工作问题简记
问题大致背景(不能详述):某种光感sensor在暗室采集的数据随屏幕亮度增加,采到的异常数据变多,需要送神经网络前过滤异常点,保证模型快速收敛。
异常检测算法没有哪个绝对好坏,需要尝试多种算法验证效果,实际问题往往还需要结合业务特点,充分利用人工经验以及数据特点,本问题的异常检测算法应用思路:
-
数据随bright增长呈现周期性规律(数据共性,业务相关):异常点分布范围和出现概率随bright增大,因此考虑对原数据dataframe分组拆分成固定bright的各组子dataframe后送pyod算法,分别剔除异常点后拼接输出
def split_df_by_col(df, col_name): sub_df_list = [] bright_list = df[col_name].unique() for bright in bright_list: temp_df = df[df[col_name].isin([bright])] sub_df = copy.deepcopy(temp_df) sub_df = sub_df.reset_index(drop=True) sub_df_list.append(sub_df) return sub_df_list def concat_df_for_out(sub_df_list): df_out = sub_df_list[0] for i in range(1, len(sub_df_list)): df_out = pd.concat([df_out, sub_df_list[i]], axis=0, ignore_index=True) print(df_out) return df_out
-
组合各种基础PoyOD算法,实现参数可配,便于后续采集的数据处理后对比效果 (目前集成了本问题效果较好的7种算法)
-
模型导入和定义
# Import models from pyod.models.abod import ABOD from pyod.models.cblof import CBLOF from pyod.models.feature_bagging import FeatureBagging from pyod.models.hbos import HBOS from pyod.models.iforest import IForest from pyod.models.knn import KNN from pyod.models.lof import LOF # Define seven outlier detection tools to be compared random_state = np.random.RandomState(42) classifiers = { 'ABOD': ABOD(), 'CBLOF': CBLOF(check_estimator=False, random_state=random_state), 'FeatureBagging': FeatureBagging(LOF(n_neighbors=35), check_estimator=False, random_state=random_state), 'HBOS': HBOS(), 'IsolationForest': IForest(random_state=random_state), 'KNN': KNN(), 'KNN_Average': KNN(method='mean') }
-
OutlierBase基类封装(PyOD的预测相关API所有模型都一样)
class OutlierDetectorBase: """ define interface of Outlier Detection, input (diff_r,diff_g,diff_b)""" diff_rgb_clf = '' diff_rgb_arr = [] def __init__(self): pass def outlier_create_clf(self, input_df): # init clfs and fit data before detect pass @staticmethod def outlier_detection_score(clf, diff_arr): train_pred = clf.labels_ train_scores = clf.decision_scores_ y_test_pred = clf.predict(diff_arr) y_test_scores = clf.decision_function(diff_arr) outliers = [] # [(i, outlier_score)] for i in range(0, len(y_test_pred)): if y_test_pred[i] == 1: # print(i, y_test_scores[i]) outliers.append((i, y_test_scores[i])) return dict(outliers) @staticmethod def outlier_test_plot(outliers): # used for plot test outliers_diff_index = outliers.keys() outliers_diff_scores = outliers.values() plt.scatter(outliers_diff_index, outliers_diff_scores) plt.show() def outlier_execute(self, input_df): # outlier detect enter self.outlier_create_clf(input_df) diff_rgb_outliers = self.outlier_detection_score(self.diff_rgb_clf, self.diff_rgb_arr) return diff_rgb_outliers
-
OutlierDetector继承OutlierBase(根据clf_name构造不同算法类型的异常点检测器)
class OutlierDetector(OutlierDetectorBase): """ KNN Outlier Detector3D""" clf_name = '' def __init__(self, clf_name): super().__init__() self.clf_name = clf_name def outlier_create_clf(self, input_df): # init knn-clf and fit data before detect X1 = input_df['diff_DN_R'].values.reshape(-1, 1) X2 = input_df['diff_DN_G'].values.reshape(-1, 1) X3 = input_df['diff_DN_B'].values.reshape(-1, 1) temp_arr = np.concatenate((X1, X2, X3), axis=1) self.diff_rgb_arr = temp_arr self.diff_rgb_clf = classifiers[self.clf_name] # init clf self.diff_rgb_clf.fit(self.diff_rgb_arr)
-
-
range-filter(人工经验,业务相关):diff_r, diff_g, diff_b这三个维度的数据应该在一个合理的范围,明显超过阈值的可以直接剔除。阈值的选取采用topK取中位数的方法确定。
def range_filter(df, col_name, k): # print('heapq.nlargest: ', heapq.nlargest(10, df[col_name])) # print('heapq.nsmallest: ', heapq.nsmallest(10, df[col_name])) max_top10 = heapq.nlargest(k, df[col_name]) min_top10 = heapq.nsmallest(k, df[col_name]) max_median = np.median(max_top10) min_median = np.median(min_top10) for index, row in df.iterrows(): if row[col_name] < min_median or row[col_name] > max_median: # print('the row need to drop: ', row) df.drop(labels=index, inplace=True) else: pass return df
-
效果示例(7种算法对比)
异常点剔除前(diff_DN_G通道):
异常点剔除后:可以看到原数据波动范围很大,最小的能波动到-120,最大能上到40;
过滤后分布更加密集,放大后能看到随bright呈现的周期性规律更加明显(原数据受异常点干扰不是很明显)
CBLOF
FeatureBagging
HBOS
IsolationForest
KNN
KNN_Average
基础结论: 对于该问题,CBLOF 效果最好, KNN 和 FeatureBagging次之, 可能与数据量不大且维度较低有关(数据量5600+, 送异常检测的特征数3)
更多推荐
所有评论(0)