77 lines
2.9 KiB
Markdown
77 lines
2.9 KiB
Markdown
---
|
||
title: "异常检测"
|
||
sidebar_label: "异常检测"
|
||
---
|
||
|
||
### 输入约定
|
||
`execute` 是算法处理的核心方法。框架调用该方法之前,在对象属性参数 `self.list` 中已经设置完毕用于异常检测的时间序列数据。
|
||
|
||
### 输出约定
|
||
`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 结束
|
||
class _MyAnomalyDetectionService(AbstractAnomalyDetectionService):
|
||
""" 定义类,从 AbstractAnomalyDetectionService 继承,并实现 AbstractAnomalyDetectionService 类的抽象方法 """
|
||
|
||
# 定义算法调用关键词,全小写ASCII码
|
||
name = 'myad'
|
||
|
||
# 该算法的描述信息(建议添加)
|
||
desc = """return the last value as the anomaly data"""
|
||
|
||
def __init__(self):
|
||
"""类初始化方法"""
|
||
super().__init__()
|
||
|
||
def execute(self):
|
||
""" 算法逻辑的核心实现"""
|
||
|
||
"""创建一个长度为 len(self.list),全部值为 1 的结果数组,然后将最后一个值设置为 -1,表示最后一个值是异常值"""
|
||
res = [1] * len(self.list)
|
||
res[-1] = -1
|
||
|
||
"""返回结果数组"""
|
||
return res
|
||
|
||
|
||
def set_params(self, params):
|
||
"""该算法无需任何输入参数,直接重载父类该函数,不处理算法参数设置逻辑"""
|
||
pass
|
||
```
|
||
|
||
将该文件保存在 `./taosanalytics/algo/ad/` 目录下,然后重启 taosanode 服务。在 TDengine 命令行接口 taos 中执行 `SHOW ANODES FULL` 就能够看到新加入的算法,然后应用就可以通过 SQL 语句调用该检测算法。
|
||
|
||
```SQL
|
||
--- 对 col 列进行异常检测,通过指定 algo 参数为 myad 来调用新添加的异常检测类
|
||
SELECT COUNT(*) FROM foo ANOMALY_WINDOW(col, 'algo=myad')
|
||
```
|
||
如果是第一次启动该 Anode, 请按照 [TDgpt 安装部署](../../management/) 里的步骤先将该 Anode 添加到 TDengine 系统中。
|
||
|
||
### 单元测试
|
||
|
||
在测试目录`taosanalytics/test`中的 anomaly_test.py 中增加单元测试用例或添加新的测试文件。框架中使用了 Python Unit test 包。
|
||
|
||
```python
|
||
def test_myad(self):
|
||
""" 测试 _IqrService 类 """
|
||
s = loader.get_service("myad")
|
||
|
||
# 设置需要进行检测的输入数据
|
||
s.set_input_list(AnomalyDetectionTest.input_list)
|
||
|
||
r = s.execute()
|
||
|
||
# 最后一个点是异常点
|
||
self.assertEqual(r[-1], -1)
|
||
self.assertEqual(len(r), len(AnomalyDetectionTest.input_list))
|
||
```
|