From f77e16301c3781b4997629ce9f365ebec27101d3 Mon Sep 17 00:00:00 2001 From: Haojun Liao Date: Tue, 12 Nov 2024 16:47:10 +0800 Subject: [PATCH] Update 03-ad.md --- docs/zh/06-advanced/06-TDgpt/06-dev/03-ad.md | 78 +++++++++----------- 1 file changed, 36 insertions(+), 42 deletions(-) diff --git a/docs/zh/06-advanced/06-TDgpt/06-dev/03-ad.md b/docs/zh/06-advanced/06-TDgpt/06-dev/03-ad.md index 9e5d781070..713f72f43c 100644 --- a/docs/zh/06-advanced/06-TDgpt/06-dev/03-ad.md +++ b/docs/zh/06-advanced/06-TDgpt/06-dev/03-ad.md @@ -3,80 +3,74 @@ title: "异常检测" sidebar_label: "异常检测" --- -### 核心方法输入与输出约定 +### 输入约定 +`execute` 是算法处理的核心方法。框架调用该方法之前,在对象属性参数 `self.list` 中已经设置完毕用于异常检测的时间序列数据。 -`execute` 是算法处理的核心方法。调用该方法的时候,`self.list` 已经设置好输入数组。 +### 输出约定 +`execute` 方法执行完成后的返回值是长度与 `self.list` 相同的数组,数组位置 -1 的标识异常值点。 +> 例如:对于输入测量值序列 [2, 2, 2, 2, 100], 假设 100 是异常点,那么方法返回的结果数组则为 [1, 1, 1, 1, -1]。 -异常检测输出结果 -`execute` 的返回值是长度与 `self.list` 相同的数组,数组位置为 -1 的即为异常值点。例如:输入数组是 [2, 2, 2, 2, 100], 如果 100 是异常点,那么返回值是 [1, 1, 1, 1, -1]。 - -预测输出结果 - -## 示例代码 +### 示例代码 +下面我们开发一个示例异常检测算法,在异常检测中,将输入时间序列值的最后一个值设置为异常值,并返回结果。 ```python import numpy as np from service import AbstractAnomalyDetectionService -# 算法实现类名称 需要以下划线 "_" 开始,并以 Service 结束,如下 _IqrService 是 IQR 异常检测算法的实现类。 -class _IqrService(AbstractAnomalyDetectionService): - """ IQR algorithm 定义类,从 AbstractAnomalyDetectionService 继承,并实现 AbstractAnomalyDetectionService 类的抽象函数 """ +# 算法实现类名称 需要以下划线 "_" 开始,并以 Service 结束 +class _MyAnomalyDetectionService(AbstractAnomalyDetectionService): + """ 定义类,从 AbstractAnomalyDetectionService 继承,并实现 AbstractAnomalyDetectionService 类的抽象方法 """ - # 定义算法调用关键词,全小写ASCII码(必须添加) - name = 'iqr' + # 定义算法调用关键词,全小写ASCII码 + name = 'myad' - # 该算法的描述信息(建议添加) - desc = """found the anomaly data according to the inter-quartile range""" + # 该算法的描述信息(建议添加) + desc = """return the last value as the anomaly data""" def __init__(self): + """类初始化方法""" super().__init__() def execute(self): - """ execute 是算法实现逻辑的核心实现,直接修改该实现即可 """ + """ 算法逻辑的核心实现""" - # self.list 是输入数值列,list 类型,例如:[1,2,3,4,5]。设置 self.list 的方法在父类中已经进行了定义。实现自己的算法,修改该文件即可,以下代码使用自己的实现替换即可。 - #lower = np.quantile(self.list, 0.25) - #upper = np.quantile(self.list, 0.75) + """创建一个长度为 len(self.list),全部值为 1 的结果数组,然后将最后一个值设置为 -1,表示最后一个值是异常值""" + res = [1] * len(self.list) + res[-1] = -1 - #min_val = lower - 1.5 * (upper - lower) - #max_val = upper + 1.5 * (upper - lower) - #threshold = [min_val, max_val] - - # 返回值是与输入数值列长度相同的数据列,异常值对应位置是 -1。例如上述输入数据列,返回数值列是 [1, 1, 1, 1, -1],表示 [5] 是异常值。 - return [-1 if k < threshold[0] or k > threshold[1] else 1 for k in self.list] + """返回结果数组""" + return res def set_params(self, params): - """该算法无需任何输入参数,直接重载父类该函数,不处理算法参数设置逻辑""" + """该算法无需任何输入参数,直接重载父类该函数,不处理算法参数设置逻辑""" pass ``` +将该文件保存在 `./taosanalytics/algo/ad/` 目录下,然后重启 taosanode 服务。然后就可以通过 SQL 语句调用该检测算法。 -## 单元测试 +```SQL +--- 对 col 列进行异常检测,通过指定 algo 参数为 myad 来调用新添加的异常检测类 +SELECT COUNT(*) FROM foo ANOMALY_DETECTION(col, 'algo=myad') +``` -在测试文件目录中的 anomaly_test.py 中增加单元测试用例。 + +### 单元测试 + +在测试目录`taosanalytics/test`中的 anomaly_test.py 中增加单元测试用例或添加新的测试文件。框架中使用了 Python Unit test 包。 ```python -def test_iqr(self): - """ 测试 _IqrService 类 """ - s = loader.get_service("iqr") +def test_myad(self): + """ 测试 _IqrService 类 """ + s = loader.get_service("myad") # 设置需要进行检测的输入数据 s.set_input_list(AnomalyDetectionTest.input_list) - # 测试 set_params 的处理逻辑 - try: - s.set_params({"k": 2}) - except ValueError as e: - self.assertEqual(1, 0) - r = s.execute() - - # 绘制异常检测结果 - draw_ad_results(AnomalyDetectionTest.input_list, r, "iqr") - - # 检查结果 + + # 最后一个点是异常点 self.assertEqual(r[-1], -1) self.assertEqual(len(r), len(AnomalyDetectionTest.input_list)) ```