Doping:使用精心设计的合成数据测试和评估异常检测器的技术

本文涉及的产品
实时数仓Hologres,5000CU*H 100GB 3个月
大数据开发治理平台 DataWorks,不限时长
智能开放搜索 OpenSearch行业算法版,1GB 20LCU 1个月
简介: 在这篇文章中,我们将探讨测试和评估异常检测器的问题(这是一个众所周知的难题),并提出了一种解决方案被称为“Doping”方法。使用Doping方法,真实数据行会被(通常是)随机修改,修改的方式是确保它们在某些方面可能成为异常值,这时应该被异常检测器检测到。然后通过评估检测器检测Doping记录的效果来评估这些检测器。

在这篇文章中,我们将探讨测试和评估异常检测器的问题(这是一个众所周知的难题),并提出了一种解决方案被称为“Doping”方法。使用Doping方法,真实数据行会被(通常是)随机修改,修改的方式是确保它们在某些方面可能成为异常值,这时应该被异常检测器检测到。然后通过评估检测器检测Doping记录的效果来评估这些检测器。

这里我们主要关注表格数据,但这个想法也可以应用到其他模式,包括文本、图像、音频、网络数据等。

测试和评估其他类型的模型

如果你熟悉异常检测,那么可能至少在某种程度上也熟悉用于回归和分类问题的预测模型。对于这类问题,我们有标记的数据,因此在调整模型时(选择最佳的预处理、特征、超参数等)评估每个选项相对简单;估算模型的准确性(在未见数据上的表现)也相对容易:我们可以简单地使用训练-验证-测试拆分或使用交叉验证。由于数据是有标记的,我们可以直接看到模型在有标记的测试数据上的表现。

但是对于异常检测,没有标记的数据,这样问题就要困难得多;因为没有客观的方式来确定由异常检测器得分最高的记录是否确实是数据集中最不寻常的。

以聚类为例,同样没有数据的标签,但至少可以衡量聚类的质量:比如可以确定簇的内部一致性以及簇之间的差异。使用某种距离度量(如曼哈顿或欧几里得距离),就可以简单的计算出簇内部记录之间的接近程度以及簇之间的距离。

给定一组可能的聚类,可以定义一个合理的度量(如轮廓分数)并确定哪种聚类更受好,或者说至少在该度量标准下更好。我们就可以为每个聚类计算一个分数,并选择看起来最有效的聚类方法。

但是对于异常检测,没有类似的东西可以使用。任何试图量化记录的异常性或确定两个记录中哪一个更异常的系统,实际上本身就是一个异常检测算法。

例如可以使用熵作为异常检测方法,并可以检查整个数据集的熵以及删除任何被识别为强异常的记录后的数据集的熵。从某种意义上说,这是有效的,因为熵是衡量异常存在的有用度量。但我们不能假设熵是这个数据集中异常的最终定义,因为异常检测的一个基本特性是没有异常的最终定义(也就是说你没法量化的判断一个值是否就是异常)。

因此,评估异常检测系统相当困难,至少使用现有的真实数据来说,实际上没有好的方法可以做到这一点。

但是可以创建合成测试数据(我们可以假设合成创建的数据主要是异常)。异常检测器则变为了评估合成记录的能力,这样就可以简化一些问题。

”篡改“数据

Doping方法主要是指将现有数据记录稍作修改,通常只更改每条记录中一个或少数几个列的值。

例如,如果正在检查的数据是公司财务绩效相关的,假设我们有包括以下特征:

  • 经营的年龄
  • 当前所有者持有的年数
  • 去年的销售次数
  • 去年的销售总额

以及其他一些特征。

典型的记录可能有这四个特征的值,例如:经营20年,当前所有者持有5年,去年10,000次销售,销售总额500,000美元。

我们可以通过调整一个值到一个罕见的值来创建一个修改版本的记录,例如,将经营的年龄设置为100年。这样做很可能任何检测器都能识别这是异常的(假设100的值是罕见的),这样我们首先能排除一些无法可靠地检测到这种修改记录的检测器。

不过我们不一定会移除异常检测器的类型(例如kNN、熵或孤立森林)本身,而是移除异常检测器的类型、预处理、超参数以及检测器的其他属性的组合。也就是说,比如某些超参数的kNN检测器表现良好,而其他超参数的则不行,我们要保留表现好超参数版的检测器。

另外在更改记录中的值时,我们不具体知道该行将如何成为异常值(假设它成为异常值),但我们可以假设大多数表格在特征之间有关联。在这个例子中,将销售额改为100,000美元可能会和销售次数有的强相关联,因为毕竟在单价相同的情况下销售次数越多,销售额就应该越多,这就是特征之间的关联。我们修改单个值会打破这种关联,这就会产生异常,我们是能够简单的判断出来的。

但是在某些表格中,特征之间没有关联,或者只有少数且弱的关联。这种情况虽然罕见,但确实会发生。对于这种情况,没有不寻常的值组合的概念,只有不寻常的单个值。听起来这种情况变得有些复杂,其实不然实际上这是一个更简单的情况:检测异常更容易(我们只需检查单个不寻常的值),评估检测器也更容易(只需检查能多好地检测不寻常的单个值)。

不过这里我们将假设特征之间存在某些关联,大多数异常将是不寻常的值组合。

使用”篡改“的数据

大多数异常检测器(少数例外)具有分割的训练和预测步骤。Doping也一样,在训练步骤中,会评估训练数据并识别数据中的正常模式(例如,记录之间的正常距离、频繁项集、聚类、特征之间的线性关系等)。然后在预测步骤中,将测试数据集(可能是用于训练的相同数据,或是不同的数据)与训练期间发现的模式进行比较,每行数据都被分配一个异常分数(或在某些情况下是二元标签)。

所以可以通过两种主要方式使用”篡改“的数据:

在训练数据中包含”篡改“数据

可以在训练数据中包含少量”篡改“记录,然后使用这些数据进行测试。这测试了在当前可用数据中检测异常值的能力。这是异常检测中的一个常见任务:给定一组数据,希望找到这个数据集中的异常值(尽管可能希望在后续数据中也找到异常值——相对于这些训练数据的规范而言,这些记录是异常的)。

这样做可以只用少量”篡改“记录进行测试,因为我们不希望显著影响数据的整体分布。然后检查是否能够识别这些异常。一个关键的测试是在训练数据中同时包含”篡改“记录的原始版本和”篡改“版本,这样可以确定检测器是否将”篡改“版本的得分显著高于同一记录的原始版本。

鉴于我们只能使用少量”篡改“记录进行测试,这个过程可能会重复多次。

如果我们能够可靠地检测数据中的”篡改“记录,就可以相当有信心地认为能够识别同一数据中的其他异常值,至少是与”篡改“记录类似的异常值

仅在测试数据中包含”篡改“数据

还有一种方法是只使用真实数据进行训练(假设这些数据大部分是非异常值),然后用真实数据和”篡改“数据进行测试。这可以在相对干净的数据上进行训练(真实数据中的某些记录将是异常值,但大多数将是典型的,且没有因”篡改“记录而导致的污染)。

这也允许我们使用可能被投入生产的实际异常检测器进行测试,因为这测试了在未来数据中检测异常值的能力。这是异常检测的另一个常见场景:有一个可以认为相对干净的数据集(要么没有异常值,要么只包含一小部分典型的异常值,且没有任何极端异常值),我们希望将未来的数据与此进行比较。

仅使用真实数据进行训练并使用真实和”篡改“数据进行测试,可以根据需要使用任何数量的”篡改“数据进行测试,因为”篡改“数据仅用于测试而不用于训练。我们可以创建一个大的、更可靠的测试数据集。

创建”篡改“数据的算法

有许多方法可以创建”篡改“数据,为简单起见,我们只介绍一种简单的方法,即数据的修改方式相当随机:修改的单元格是随机选择的,替换原始值的新值也是随机创建的。

这样做虽然有可能某些修改的记录并非真正的异常,但在大多数情况下,随机分配的值将破坏特征之间的一个或多个关联。所以可以假设”篡改“记录大多是异常的,尽管根据它们的创建方式,可能只是略微如此。

代码示例

我们通过一个实例,取一个真实数据集,修改它,并测试如何检测这些修改。使用一个在OpenML上可用的名为鲍鱼(abalone)的数据集

尽管可以进行其他预处理,但为了简单起见我们只对分类特征进行独热编码,并使用RobustScaler缩放数值特征,因为这是最基本的预处理了。

我们这里测试三种异常检测器,分别是孤立森林(Isolation Forest)、局部异常因子(LOF)和集成协同异常检测(ECOD),这些都可以在PyOD库中找到。

我们还使用孤立森林来做清理数据(在任何训练或测试之前移除任何强异常值)。这一步虽然不是必需的,但在异常检测中常常是有用的。

我们在原始数据上进行训练,并使用原始数据和”篡改“数据进行测试。(上面说的第二种方法)

 import numpy as np
 import pandas as pd
 from sklearn.datasets import fetch_openml
 from sklearn.preprocessing import RobustScaler
 import matplotlib.pyplot as plt
 import seaborn as sns
 from pyod.models.iforest import IForest
 from pyod.models.lof import LOF
 from pyod.models.ecod import ECOD

 # Collect the data
 data = fetch_openml('abalone', version=1) 
 df = pd.DataFrame(data.data, columns=data.feature_names)
 df = pd.get_dummies(df)
 df = pd.DataFrame(RobustScaler().fit_transform(df), columns=df.columns)

 # Use an Isolation Forest to clean the data
 clf = IForest() 
 clf.fit(df)
 if_scores = clf.decision_scores_
 top_if_scores = np.argsort(if_scores)[::-1][:10]
 clean_df = df.loc[[x for x in df.index if x not in top_if_scores]].copy()

 # Create a set of doped records
 doped_df = df.copy() 
 for i in doped_df.index:
   col_name = np.random.choice(df.columns)
   med_val = clean_df[col_name].median()
   if doped_df.loc[i, col_name] > med_val:
     doped_df.loc[i, col_name] = \   
       clean_df[col_name].quantile(np.random.random()/2)
   else:
     doped_df.loc[i, col_name] = \
        clean_df[col_name].quantile(0.5 + np.random.random()/2)

 # Define a method to test a specified detector. 
 def test_detector(clf, title, df, clean_df, doped_df, ax): 
   clf.fit(clean_df)
   df = df.copy()
   doped_df = doped_df.copy()
   df['Scores'] = clf.decision_function(df)
   df['Source'] = 'Real'
   doped_df['Scores'] = clf.decision_function(doped_df)
   doped_df['Source'] = 'Doped'
   test_df = pd.concat([df, doped_df])
   sns.boxplot(data=test_df, orient='h', x='Scores', y='Source', ax=ax)
   ax.set_title(title)

 # Plot each detector in terms of how well they score doped records 
 # higher than the original records
 fig, ax = plt.subplots(nrows=1, ncols=3, sharey=True, figsize=(10, 3)) 
 test_detector(IForest(), "IForest", df, clean_df, doped_df, ax[0])
 test_detector(LOF(), "LOF", df, clean_df, doped_df, ax[1])
 test_detector(ECOD(), "ECOD", df, clean_df, doped_df, ax[2])
 plt.tight_layout()
 plt.show()

为了创建”篡改“数据,我们复制了完整的原始记录集,因此”篡改“数据的数量与原始记录相等。对于每条”篡改“记录,我们随机选择一个特征进行修改。如果原始值低于中位数,我们就创建一个高于中位数的随机值;如果原始值高于中位数,我们创建一个低于中位数的随机值。

我们看到IF对”篡改“记录的评分更高,但不是很明显。LOF在区分”篡改“记录方面做得很好,至少对于这种形式的修改是能够鉴别出来的。而ECOD是一种检测器,仅检测异常小或异常大的单个值,而不测试异常组合。而我们这里的修改不会产生极值,只有不寻常的组合,所以ECOD无法将”篡改“与原始记录区分开来。

这个例子使用箱线图比较检测器,但通常我们会使用一个客观的评分,比如使用AUROC分数来评估每个检测器。通常也会测试许多模型类型、预处理和参数的组合。

一些其他的替代方法

我们上面介绍的方法倾向于创建违反特征间正常关联的”篡改“记录,也可以使用其他修改技术来增加这种可能性。例如,首先考虑分类列,我们可以选择一个新值,确保满足两个条件:

  1. 新值与原始值不同
  2. 新值与行中其他值预测的值不同,可以创建一个预测模型来预测这一列的当前值,例如使用随机森林分类器。

对于数值数据,可以通过将每个数值特征划分为四个四分位数(或一些数量的分位数,但至少是三个)来实现等效目标。对于数值特征中的每个新值,我们选择一个值确保:

  1. 新值与原始值处于不同的四分位数
  2. 新值与根据行中其他值预测的四分位数不同

例如,如果原始值在Q1,预测值在Q2,那么我们可以随机选择一个值在Q3或Q4中。这样新值很可能会违反特征间的正常关系。

创建一套测试数据集

一旦数据被修改了,就没有确定量化的方式来说明记录有多异常。但是可以假设平均而言,修改的特征越多,修改的程度越大,”篡改“记录就越异常。我们可以利用这一点,不仅创建单一的测试,而且创建多个测试组合,这使我们能够更准确地评估异常检测器。

例如,我们可以创建一组非常明显的”篡改“记录(每条记录中修改多个特征,每个都与原始值显著不同),一组非常微妙的”篡改“记录(只修改一个特征,且与原始值差异不大),以及许多中间难度级别的记录。这可以帮助区分不同的检测器。

所以可以创建一套测试集,每个测试集根据修改的特征数量和修改的程度具有(粗略估计的)难度级别。还可以有不同的集合修改不同的特征,因为某些特征中的异常值可能更相关,或者检测起来可能更容易或更困难。

这样任何执行的”篡改“都代表了如果出现在真实数据中将会感兴趣的异常类型。理想情况下,”篡改“记录的组合也很好地覆盖了异常检测的范围。

如果满足这些条件,并创建了多个测试集,这对于选择最佳表现的检测器和估算它们在未来数据上的性能非常有力。我们虽然无法预测将检测到多少异常值,也无法知道会看到什么程度的结果——这些在很大程度上取决于将数据(在异常检测的背景下这是很难预测的)。但是可以得到一个不错的感觉,了解可能检测到哪些类型的异常值,哪些则不会。

更重要的是,我们也能够创建一个有效的异常检测器集成。在异常检测中,集成通常对大多数项目来说是必需的。鉴于一些检测器会捕捉到某些类型的异常值而错过其他类型,而其他检测器则会捕捉并错过另外的类型,我们需要通过使用多个检测器可靠地捕捉到异常值范围。

创建集成本身就是一个庞大且复杂的领域,与预测模型的集成不同。但是对于这种方法,我们可以指出了解每个检测器能检测哪些类型的异常值,同时我们也可以得到哪些检测器是多余的,哪些可以检测到大多数其他检测器无法检测到的异常值。因为通过组合我们知道了哪些值被修改了,虽然有一部分人工的工作,但是得到的结果是我们最想要的。

总结

评估任何给定的异常检测器在当前数据中检测异常的效果有多好是困难的,评估其在未来(未见)数据上的表现更是难上加难。同给定两个或更多的异常检测器,评估哪个会做得更好,无论是在当前数据还是未来数据上,都非常困难。

不过,我们可以使用合成数据来估计这些情况。在本文中,我们快速地回顾了一种”篡改“真实记录并评估能否将这些记录区分的方法。尽管不完美但这个方法可以在异常检测中很多时候没有其他实际的替代方法时使用。

Doping方法通过人为创建异常数据点来测试和训练异常检测算法的鲁棒性。这种方法的优势在于可以在没有自然异常数据的情况下测试检测器的灵敏度和准确性。通过这种方式,可以模拟不同类型和程度的数据异常,从而更全面地评估异常检测器的表现。

虽然这种方法不能完全预测检测器在处理真实世界数据时的表现,但它提供了一个有用的工具来增强我们对异常检测器性能的理解,并帮助我们优化检测器配置,以便更好地处理各种数据异常情况。通过反复试验和评估,我们可以逐步改进异常检测技术,使其更加适应不断变化的数据特征和异常行为。

本文的数据

https://avoid.overfit.cn/post/29f12661ea6145b99a7e04717e892174

作者:W Brett Kennedy

目录
相关文章
|
7天前
|
测试技术 API C#
C#使用Bogus生成测试数据
C#使用Bogus生成测试数据
14 1
|
11天前
|
存储 安全 测试技术
移动应用的安全测试与加固技术深度解析
【8月更文挑战第2天】随着移动互联网的发展,移动应用成为生活必需,但安全威胁也随之加剧。本文深入探讨移动应用的安全测试与加固技术,包括权限访问、数据加密、安全协议、组件安全测试及渗透测试等内容,同时覆盖源代码、运行时环境、数据传输存储及业务逻辑加固等方面,为开发者提供全面指导,以保护用户数据和企业资产安全。
38 12
|
5天前
|
关系型数据库 MySQL Python
[python]使用faker库生成测试数据
[python]使用faker库生成测试数据
|
5天前
|
机器学习/深度学习 人工智能 物联网
探索软件测试的前沿技术与未来趋势
在数字化时代的浪潮中,软件测试作为保障软件质量的重要环节,正经历着前所未有的变革。本文将深入探讨当前软件测试领域的最新技术进展,包括自动化测试、人工智能在测试中的应用、以及云测试平台的发展等。同时,文章也将对软件测试的未来发展趋势进行预测,为读者揭示一个更加智能化、高效化的软件测试新时代。
|
21天前
|
机器学习/深度学习 人工智能 算法
探索软件测试的前沿技术:AI与自动化的融合
在数字化时代的浪潮中,软件测试领域正经历着前所未有的变革。本文深入探讨了人工智能(AI)和自动化技术如何重塑软件测试的未来。通过分析最新的行业报告、案例研究和专家访谈,我们揭示了这些技术如何提升测试效率、准确性和灵活性。文章还讨论了实施这些技术的可能挑战和解决方案,为读者提供了宝贵的行业见解和实用建议。
77 6
|
18天前
|
机器学习/深度学习 人工智能 自然语言处理
探索自动化测试的前沿技术与实践
随着科技的快速发展,软件测试领域也迎来了新的变革。自动化测试作为一种提高测试效率和准确性的有效手段,正逐渐成为软件开发过程中不可或缺的一部分。本文将深入探讨自动化测试的最新技术动态,包括人工智能在测试中的应用、持续集成/持续部署(CI/CD)流程中的自动化策略,以及跨平台测试框架的创新。同时,文章还将分享一些实用的自动化测试最佳实践,帮助读者构建更加高效、可靠的自动化测试体系。让我们一起迈向自动化测试的新纪元,解锁软件质量保障的新可能。
20 2
|
18天前
|
机器学习/深度学习 人工智能 测试技术
探索自动化测试的前沿技术
本文深入探讨了自动化测试领域的最新进展,包括人工智能(AI)和机器学习(ML)在自动化测试中的应用、持续集成/持续部署(CI/CD)流程中的自动化测试策略以及云测试平台的兴起。通过分析这些技术的实际应用案例,文章旨在为读者提供对当前软件测试行业趋势的全面了解,并激发对未来可能发展方向的思考。
16 1
|
12天前
|
机器学习/深度学习 人工智能 自然语言处理
探索自动化测试的边界:如何有效整合AI技术提升软件质量
随着人工智能技术的飞速发展,其在软件测试领域的应用逐渐深入。本文将探讨自动化测试与AI结合的现状和挑战,分析AI在提升测试效率、发现深层次缺陷等方面的潜力,并提出实现这一融合的实践策略。
18 0
|
12天前
|
机器学习/深度学习 自然语言处理 算法
测试FunAudioLLM在性能、功能、技术先进性等跟国际知名语音大模型进行比较。
测试FunAudioLLM在性能、功能、技术先进性等跟国际知名语音大模型进行比较。
18 0
|
14天前
|
机器学习/深度学习 人工智能 算法
探索自动化测试的前沿技术
【7月更文挑战第30天】在软件开发的浪潮中,自动化测试已成为确保产品质量和效率的关键因素。本文将探讨自动化测试的最新进展,包括AI与机器学习的集成、云测试服务的发展,以及持续集成/持续部署(CI/CD)流程中的测试自动化实践。我们将深入分析这些技术如何改变测试策略,提高效率,并预测它们对未来软件测试领域的影响。
11 0
下一篇
云函数