异常检测(Snowflake Cortex ML 函数)¶
备注
异常检测是 Snowflake Cortex 的一部分,Snowflake Cortex 是 Snowflake 完全托管的智能 AI 和 ML 服务。此功能是 Snowflake Cortex ML 函数套件的一部分。
概述¶
异常检测是识别数据中异常值的过程。Snowflake Cortex 产品中的异常检测功能允许训练模型,以检测时序数据中的异常值。异常值(偏离预期范围的数据点)可能会对从数据派生的统计数据以及使用这些数据训练的机器学习模型产生巨大影响。因此,发现和移除异常值有助于提高结果质量。
在没有明显原因的情况下,检测异常值也可用于查明流程中问题或偏差的根源。例如:
确定日志记录管道何时开始出现问题。
确定 Snowflake 计算成本高于预期的日期。
异常检测适用于单序列或多序列数据。多序列数据表示事件的多个独立线程。例如,如果存在多个商店的销售数据,则可以通过单个模型根据商店标识符分别查看每个商店的销售额。
数据必须包含:
时间戳列,该列应具有固定频率(例如每小时、每 5 分钟等)。
目标列,代表每个时间戳下的某些相关数量。
要检测时间序列数据中的异常值,请使用 Snowflake 内置类 ANOMALY_DETECTION (SNOWFLAKE.ML),然后执行以下步骤:
创建一个异常检测对象,传入对训练数据的引用。
此对象会将模型拟合到您提供的训练数据。该模型是一个架构级对象。
使用此异常检测模型对象,调用 <model_name>!DETECT_ANOMALIES 方法来检测异常,并传入对要分析的数据的引用。
该方法使用模型来识别数据中的异常值。
异常检测与 预测 密切相关。异常检测模型生成与要检查异常的数据相同的时间段的预测,然后将实际数据与预测进行比较以识别异常值。
重要
法律声明。 此 Snowflake Cortex ML 函数由机器学习技术提供支持。机器学习技术和提供的结果可能不准确、不合适或较为片面。基于机器学习输出(包括内置在自动管道中的输出)的决策应有人工监督和审查流程,以确保模型生成的内容准确无误。Snowflake Cortex ML 函数查询将被视为任何其他 SQL 查询,并可能被视为 元数据。
元数据。 当您使用 Snowflake Cortex ML 函数时,除了 元数据字段 中提及的内容外,Snowflake 还会记录 ML 函数返回的通用错误消息。这些错误日志可帮助我们排查出现的问题,并改进这些函数以更好地满足您的需求。
有关更多信息,请参阅 Snowflake AI 信任与安全 FAQ。
关于异常检测的算法¶
异常检测算法由 `梯度提升机<https://en.wikipedia.org/wiki/Gradient_boosting>`_ (GBM) 提供支持。与 ARIMA (link removed) 模型一样,它使用差分变换对具有非平稳趋势的数据进行建模,并使用历史目标数据的自回归滞后期作为模型变量。
此外,该算法使用历史目标数据的滚动平均值来帮助预测趋势,并使用时间戳数据自动生成循环日历变量(例如星期几和一年中的一周)。
您可以仅使用历史目标值和时间戳数据拟合模型,也可以加入可能影响目标值的外生数据(变量)。外生变量可以是数值或分类值,也可以是 NULL(不会删除包含 NULLs 外生变量的行)。
在对分类变量进行训练时,该算法不依赖单次编码,因此可以使用多维度(高基数)的分类数据。
如果模型包含外生变量,则在将来检测异常时,必须在时间戳处为这些变量提供值。适当的外生变量包括天气数据(温度、降雨量)、公司特定信息(历史和计划的公司假期、广告活动、活动时间表),或者您认为可能有助于预测目标变量的任何其他外部因素。
也可以选择使用单独的布尔列将单个历史行标记为异常或非异常。
预测区间 是上限和下限内的估算值范围,其中特定数据的百分比可能会下降。例如,值 0.99 表示 99% 的数据可能出现在区间内。异常检测模型会将超出预测区间的任何数据标识为异常。您可以指定预测区间或使用默认值 0.99。您可能希望将此值设置为高度接近于 1.0;如 0.9999 甚至更接近的值。
重要
Snowflake 计划会不时完善异常检测算法,并将通过定期 Snowflake 发布过程推出任何改进。您无法恢复到该功能的先前版本,但使用先前版本创建的模型将继续使用该版本进行异常检测。
限制¶
您无法选择或调整异常检测算法。特别是,该算法不提供替换趋势、季节性或季节性幅度的参数;这些参数是从数据推断出来的。
主要异常检测算法的最小行数为每个时间序列 12 行。对于观测值介于 2 到 11 之间的时间序列,异常检测会产生一个“朴素”的结果,其中所有预测值都等于上次观测的目标值。对于带标签的异常检测案例,使用的观测值数量是标签列为 false 的行数。
可接受的最小数据粒度为一秒。(时间戳之间的间隔不得短于一秒。)
季节性组件的最小精确度为 1 分钟。该函数无法在较小时间增量下检测到循环模式。
数据中的时间戳必须表示固定的时间间隔。如果输入数据不规则,请在训练模型时尝试在时间戳列上使用 DATE_TRUNC 或 TIME_SLICE。
自回归特征的“季节长度”与输入频率相关联(每小时数据为 24,每日数据为 7,依此类推)。
异常检测模型一旦经过训练,就是不可变的。您不能使用新数据更新现有模型;您必须训练一个全新模型。模型不支持版本控制。一般来说,您应该根据新数据接收频率定期对模型进行重新训练,例如每周一次或每月一次,以帮助模型跟上不断变化的趋势。
此功能仅相对于训练数据检测测试数据中的异常。它无法检测训练数据中的异常。由于训练数据是模型的来源,因此从定义来看,相对于自身是没有异常值的。确保训练数据涵盖没有实际异常值的典型时间段,或在布尔列中标记为此类异常值的已知异常值。
您无法克隆模型或跨角色或账户共享模型。克隆架构或数据库时,将会跳过模型对象。
您不能 复制 ANOMALY_DETECTION 类的实例。
异常检测准备工作¶
在使用异常检测之前,您必须:
选择要在其中训练和运行模型的 虚拟仓库。
您可能还想 修改搜索路径 以包含 SNOWFLAKE.ML。
选择虚拟仓库¶
Snowflake 虚拟仓库 为该功能提供训练和使用机器学习模型所需的计算资源。本节提供的一般指导说明了如何出于此目的选择最佳大小和类型的仓库,重点介绍训练步骤(该过程中最耗时且内存最密集的部分)。
单序列数据训练¶
对于基于单序列数据训练的模型,应根据训练数据的大小选择仓库类型。标准仓库的 Snowpark 内存限制 较低,更适合行数或外生特征较少的训练作业。如果训练数据不包含任何外生特征,数据集的行数不超过 500 万行,就可以基于标准仓库进行训练。如果训练数据使用 5 个或更多外生特征,则最大行数更少。否则,Snowflake 建议使用 Snowpark 优化型仓库 完成更大规模的训练作业。
一般来说,对于单序列数据,仓库规模越大,训练时间越短,内存限制也越高。粗略的经验法则是,训练时间与时间序列的行数成正比。例如,在 XS 标准仓库上,对 100,000 行数据集进行训练大约需要 30 秒。在 1,000,000 行数据集上进行训练大约需要 140 秒。
为了获得最佳性能,Snowflake 建议使用没有其他并发工作负载的专用仓库来训练模型。
多序列数据训练¶
与单序列数据一样,我们建议根据最大时间序列中的行数选择仓库类型。如果最大时间序列包含的行数超过 500 万行,则训练作业可能会超出标准仓库的内存限制。
与单系列数据不同,多系列数据在较大的仓库规模上训练速度要快得多。以下数据点可以指导您进行选择。
仓库类型和大小 |
时间序列数 |
每个时间序列的行数 |
训练时间(秒) |
---|---|---|---|
Standard XS |
1 |
100,000 |
38 秒 |
Standard XS |
10 |
100,000 |
112 秒 |
Standard XS |
100 |
100,000 |
594 秒 |
Standard XL |
10 |
100,000 |
34 秒 |
Standard XL |
100 |
100,000 |
114 秒 |
Standard XL |
1000 |
100,000 |
572 秒 |
Snowpark-Optimized XL |
10 |
100,000 |
74 秒 |
Snowpark-Optimized XL |
100 |
100,000 |
215 秒 |
Snowpark-Optimized XL |
1000 |
100,000 |
1429 秒 |
检测异常¶
无论仓库规模如何,推理步骤大约需要 1 秒来处理所输入数据集中的 500 行。
授予创建异常检测对象的权限¶
训练异常检测模型会生成架构级对象。因此,用于创建模型的角色必须对将在其中创建模型的架构具有 CREATE SNOWFLAKE.ML.ANOMALY_DETECTION 权限,以便允许模型存储在相应位置。此权限类似于其他架构权限,如 CREATE TABLE 或 CREATE VIEW。
Snowflake 建议您创建一个需要检测异常的人员使用的角色,该角色名为 analyst
。
在以下示例中,admin
角色是架构 admin_db.admin_schema
的所有者。该 analyst
角色需要在此架构中创建模型。
USE ROLE admin;
GRANT USAGE ON DATABASE admin_db TO ROLE analyst;
GRANT USAGE ON SCHEMA admin_schema TO ROLE analyst;
GRANT CREATE SNOWFLAKE.ML.ANOMALY_DETECTION ON SCHEMA admin_db.admin_schema TO ROLE analyst;
要使用此架构,用户将承担 analyst
角色:
USE ROLE analyst;
USE SCHEMA admin_db.admin_schema;
如果角色 analyst
在数据库 analyst_db
中具有 CREATE SCHEMA 权限,则该角色可以创建新架构 analyst_db.analyst_schema
并在该架构中创建异常检测模型:
USE ROLE analyst;
CREATE SCHEMA analyst_db.analyst_schema;
USE SCHEMA analyst_db.analyst_schema;
要撤消角色对架构的模型创建权限,请使用 REVOKE <privileges>:
REVOKE CREATE SNOWFLAKE.ML.ANOMALY_DETECTION ON SCHEMA admin_db.admin_schema FROM ROLE analyst;
为示例设置数据¶
以下部分中的示例使用示例数据集,该数据集包含不同商店中商品的每日销售额以及每日天气数据(湿度和温度)。该数据集还包含一个列,用于指示当天是否为假日。
执行以下语句以创建名为
historical_sales_data
的表,其中包含模型的训练数据:
CREATE OR REPLACE TABLE historical_sales_data ( store_id NUMBER, item VARCHAR, date TIMESTAMP_NTZ, sales FLOAT, label BOOLEAN, temperature NUMBER, humidity NUMBER, holiday VARCHAR); INSERT INTO historical_sales_data VALUES (1, 'jacket', to_timestamp_ntz('2020-01-01'), 2.0, false, 50, 0.3, 'new year'), (1, 'jacket', to_timestamp_ntz('2020-01-02'), 3.0, false, 52, 0.3, null), (1, 'jacket', to_timestamp_ntz('2020-01-03'), 5.0, false, 54, 0.2, null), (1, 'jacket', to_timestamp_ntz('2020-01-04'), 30.0, true, 54, 0.3, null), (1, 'jacket', to_timestamp_ntz('2020-01-05'), 8.0, false, 55, 0.2, null), (1, 'jacket', to_timestamp_ntz('2020-01-06'), 6.0, false, 55, 0.2, null), (1, 'jacket', to_timestamp_ntz('2020-01-07'), 4.6, false, 55, 0.2, null), (1, 'jacket', to_timestamp_ntz('2020-01-08'), 2.7, false, 55, 0.2, null), (1, 'jacket', to_timestamp_ntz('2020-01-09'), 8.6, false, 55, 0.2, null), (1, 'jacket', to_timestamp_ntz('2020-01-10'), 9.2, false, 55, 0.2, null), (1, 'jacket', to_timestamp_ntz('2020-01-11'), 4.6, false, 55, 0.2, null), (1, 'jacket', to_timestamp_ntz('2020-01-12'), 7.0, false, 55, 0.2, null), (1, 'jacket', to_timestamp_ntz('2020-01-13'), 3.6, false, 55, 0.2, null), (1, 'jacket', to_timestamp_ntz('2020-01-14'), 8.0, false, 55, 0.2, null), (2, 'umbrella', to_timestamp_ntz('2020-01-01'), 3.4, false, 50, 0.3, 'new year'), (2, 'umbrella', to_timestamp_ntz('2020-01-02'), 5.0, false, 52, 0.3, null), (2, 'umbrella', to_timestamp_ntz('2020-01-03'), 4.0, false, 54, 0.2, null), (2, 'umbrella', to_timestamp_ntz('2020-01-04'), 5.4, false, 54, 0.3, null), (2, 'umbrella', to_timestamp_ntz('2020-01-05'), 3.7, false, 55, 0.2, null), (2, 'umbrella', to_timestamp_ntz('2020-01-06'), 3.2, false, 55, 0.2, null), (2, 'umbrella', to_timestamp_ntz('2020-01-07'), 3.2, false, 55, 0.2, null), (2, 'umbrella', to_timestamp_ntz('2020-01-08'), 5.6, false, 55, 0.2, null), (2, 'umbrella', to_timestamp_ntz('2020-01-09'), 7.3, false, 55, 0.2, null), (2, 'umbrella', to_timestamp_ntz('2020-01-10'), 8.2, false, 55, 0.2, null), (2, 'umbrella', to_timestamp_ntz('2020-01-11'), 3.7, false, 55, 0.2, null), (2, 'umbrella', to_timestamp_ntz('2020-01-12'), 5.7, false, 55, 0.2, null), (2, 'umbrella', to_timestamp_ntz('2020-01-13'), 6.3, false, 55, 0.2, null), (2, 'umbrella', to_timestamp_ntz('2020-01-14'), 2.9, false, 55, 0.2, null);
执行以下语句以创建名为
new_sales_data
的表,其中包含要分析的数据:
CREATE OR REPLACE TABLE new_sales_data ( store_id NUMBER, item VARCHAR, date TIMESTAMP_NTZ, sales FLOAT, temperature NUMBER, humidity NUMBER, holiday VARCHAR); INSERT INTO new_sales_data VALUES (1, 'jacket', to_timestamp_ntz('2020-01-16'), 6.0, 52, 0.3, null), (1, 'jacket', to_timestamp_ntz('2020-01-17'), 20.0, 53, 0.3, null), (2, 'umbrella', to_timestamp_ntz('2020-01-16'), 3.0, 52, 0.3, null), (2, 'umbrella', to_timestamp_ntz('2020-01-17'), 70.0, 53, 0.3, null);
训练、使用、查看、删除和更新模型¶
使用 CREATE SNOWFLAKE.ML.ANOMALY_DETECTION 创建和训练模型。模型是在您提供的数据集上训练的。
CREATE SNOWFLAKE.ML.ANOMALY_DETECTION mydetector(...);
有关 SNOWFLAKE.ML.ANOMALY_DETECTION 构造函数的完整详细信息,请参阅 ANOMALY_DETECTION (SNOWFLAKE.ML)。有关创建模型的示例,请参阅 检测异常。
备注
SNOWFLAKE.ML.ANOMALY_DETECTION 使用有限的权限运行,因此默认情况下它无权访问您的数据。因此,您必须将表和视图作为 引用 传递,以便传递调用方的权限。还可以提供 查询引用,而不是对表或视图的引用。
要检测异常,请调用模型的 <model_name>!DETECT_ANOMALIES 方法:
CALL mydetector!DETECT_ANOMALIES(...)
要查看模型列表,请使用 SHOW SNOWFLAKE.ML.ANOMALY_DETECTION 命令:
SHOW SNOWFLAKE.ML.ANOMALY_DETECTION;
要移除模型,请使用 DROP SNOWFLAKE.ML.ANOMALY_DETECTION 命令:
DROP SNOWFLAKE.ML.ANOMALY_DETECTION <name>;
要更新模型,请将其删除并训练新模型。 模型是不可变的,不能就地更新。
检测异常¶
以下部分演示如何使用异常检测来检测异常值。这些部分提供了针对单个时间序列、多个时间序列、有和没有外生变量的情况、用户定义的预测区间以及受监督(已标记)方法检测异常的示例。
为单个时间序列检测异常(无监督)¶
要检测数据中的异常情况,请执行以下操作:
使用历史数据训练异常检测模型。
使用经过训练的异常检测模型检测历史数据或投影数据中的异常。测试数据中的时间戳必须按时间顺序遵循训练数据中的时间戳。训练模型至少需要 2 个数据点,非朴素结果至少需要 12 个数据点,非线性结果至少需要 60 个数据点。
有关创建和使用模型时使用的参数的信息,请参阅 ANOMALY_DETECTION (SNOWFLAKE.ML)。
训练异常检测模型¶
要创建异常检测模型对象,请执行 CREATE SNOWFLAKE.ML.ANOMALY_DETECTION 命令。
例如,假设您要分析 store_id
为 1 的商店中夹克的销售额:
创建视图或设计查询,返回用于训练异常检测模型的数据。
对于此示例,请执行 CREATE VIEW 命令以创建名为
view_with_training_data
的视图,其中包含日期和销售信息:CREATE OR REPLACE VIEW view_with_training_data AS SELECT date, sales FROM historical_sales_data WHERE store_id=1 AND item='jacket';
创建异常检测对象,并使用该视图中的数据训练其模型。
在本示例中,执行 CREATE SNOWFLAKE.ML.ANOMALY_DETECTION 命令以创建名为
basic_model
的异常检测对象。传入以下实参:CREATE OR REPLACE SNOWFLAKE.ML.ANOMALY_DETECTION basic_model( INPUT_DATA => SYSTEM$REFERENCE('VIEW', 'view_with_training_data'), TIMESTAMP_COLNAME => 'date', TARGET_COLNAME => 'sales', LABEL_COLNAME => '');
标签列的目的是告诉模型哪些行已知存在异常。由于此示例使用无监督训练,因此无需使用标签列。传递一个空字符串作为标签列的名称。
小技巧
如果不想为 SELECT 实参创建视图,可以将 INPUT_DATA 语句用作内联视图。无需调用 SYSTEM$REFERENCE 来创建对表视图的引用,而是调用 SYSTEM$QUERY_REFERENCE 来创建对 SELECT 语句的查询引用。用反斜杠来转义任何单引号和其他特殊字符。
例如:
CREATE OR REPLACE SNOWFLAKE.ML.ANOMALY_DETECTION basic_model( INPUT_DATA => SYSTEM$QUERY_REFERENCE( 'SELECT date, sales FROM historical_sales_data WHERE store_id=1 AND item=\'jacket\'' ), TIMESTAMP_COLNAME => 'date', TARGET_COLNAME => 'sales', LABEL_COLNAME => '');
如果命令执行成功,则会显示一条消息,表明已成功创建异常检测实例:
+--------------------------------------------+ | status | +--------------------------------------------+ | Instance basic_model successfully created. | +--------------------------------------------+
使用异常检测模型检测异常¶
创建异常检测对象以训练模型,并将其存储在架构中。若要使用异常检测对象检测异常,请调用该对象的 <model_name>!DETECT_ANOMALIES 方法。例如:
创建视图或设计查询,以便返回数据进行分析。
对于此示例,请执行 CREATE VIEW 命令以创建名为
view_with_data_to_analyze
的视图,其中包含日期和销售信息:CREATE OR REPLACE VIEW view_with_data_to_analyze AS SELECT date, sales FROM new_sales_data WHERE store_id=1 and item='jacket';
使用异常检测模型的对象(在此示例中为 您之前创建的
basic_model
),调用 <model_name>!DETECT_ANOMALIES 方法:CALL basic_model!DETECT_ANOMALIES( INPUT_DATA => SYSTEM$REFERENCE('VIEW', 'view_with_data_to_analyze'), TIMESTAMP_COLNAME =>'date', TARGET_COLNAME => 'sales' );
该方法会返回一个表,其中包含视图
view_with_data_to_analyze
中当前数据的行以及检测器的预测结果。有关此表中各列的说明,请参阅 返回。
输出
为了便于阅读,对结果进行了四舍五入。
+--------+-------------------------+----+----------+--------------+--------------+------------+--------------+--------------+ | SERIES | TS | Y | FORECAST | LOWER_BOUND | UPPER_BOUND | IS_ANOMALY | PERCENTILE | DISTANCE | +--------|-------------------------+----+----------+--------------+--------------+------------+--------------+--------------| | NULL | 2020-01-16 00:00:00.000 | 6 | 4.6 | -7.185885251 | 16.385885251 | False | 0.6201873452 | 0.3059728606 | | NULL | 2020-01-17 00:00:00.000 | 20 | 9 | -2.785885251 | 20.785885251 | False | 0.9918932208 | 2.404072476 | +--------+-------------------------+----+----------+--------------+--------------+------------+--------------+--------------|
若要将结果直接保存到表中,请使用以下代码:
BEGIN
CALL basic_model!DETECT_ANOMALIES(
INPUT_DATA => SYSTEM$REFERENCE('VIEW', 'view_with_data_to_analyze'),
TIMESTAMP_COLNAME =>'date',
TARGET_COLNAME => 'sales'
);
LET x := SQLID;
CREATE TABLE my_anomalies AS SELECT * FROM TABLE(RESULT_SCAN(:x));
END;
SELECT * FROM my_anomalies;
尽管上面的代码使用 RESULT_SCAN,但 即使 多个进程同时运行,它也不受竞争条件的约束。上述模型调用的结果将确定性地存储到 my_anomalies
表中。
使用标记数据训练异常检测模型¶
在前面的示例中,模型的结果似乎不准确。这可能是因为:
异常检测模型是使用非常少的输入数据上训练的。
2020 年 1 月 3 日售出的夹克数量较多 (30)。这会使预测结果略微上升,并增加预测区间的大小。
若要提高异常检测模型的准确性,可以包含更多训练数据或标记训练数据(监督训练)。标记的训练数据具有一个附加的布尔列,用于指示每行是否存在已知异常。标记可以帮助异常检测模型避免过度拟合训练数据中的已知异常。
若要在训练数据中包含标记数据,请在 CREATE SNOWFLAKE.ML.ANOMALY_DETECTION 命令的 LABEL_COLNAME 构造函数实参中指定包含标签的列。例如:
创建视图或设计查询,以返回包含训练数据的标签。
对于此示例,请执行 CREATE VIEW 命令,在名为
label
的列中创建一个名为view_with_labeled_data
的视图,其中包含标记:CREATE OR REPLACE VIEW view_with_labeled_data_for_training AS SELECT date, sales, label FROM historical_sales_data WHERE store_id=1 and item='jacket';
为异常检测模型创建一个对象,利用该视图中的数据训练模型。
在本示例中,执行 CREATE SNOWFLAKE.ML.ANOMALY_DETECTION 命令以创建名为
model_trained_with_labeled_data
的异常检测对象。以下语句创建异常检测对象:CREATE OR REPLACE SNOWFLAKE.ML.ANOMALY_DETECTION model_trained_with_labeled_data( INPUT_DATA => SYSTEM$REFERENCE('VIEW', 'view_with_labeled_data_for_training'), TIMESTAMP_COLNAME => 'date', TARGET_COLNAME => 'sales', LABEL_COLNAME => 'label' );
使用此新的异常检测模型,调用 <model_name>!DETECT_ANOMALIES 方法,传入您在 为单个时间序列检测异常(无监督) 中使用的相同实参:
CALL model_trained_with_labeled_data!DETECT_ANOMALIES( INPUT_DATA => SYSTEM$REFERENCE('VIEW', 'view_with_data_to_analyze'), TIMESTAMP_COLNAME =>'date', TARGET_COLNAME => 'sales' );
该方法会返回一个表,其中包含视图
view_with_data_to_analyze
中当前数据的行以及检测器的预测结果。有关此表中各列的说明,请参阅 返回。
输出
为了便于阅读,对结果进行了四舍五入。
+--------+-------------------------+----+----------+---------------+--------------+------------+--------------+------------+ | SERIES | TS | Y | FORECAST | LOWER_BOUND | UPPER_BOUND | IS_ANOMALY | PERCENTILE | DISTANCE | +--------|-------------------------+----+----------+---------------+--------------+------------+--------------+------------| | NULL | 2020-01-16 00:00:00.000 | 6 | 6 | 0.82 | 11.18 | False | 0.5 | 0 | | NULL | 2020-01-17 00:00:00.000 | 20 | 6 | -0.39 | 12.33 | True | 0.99 | 5.70 | +--------+-------------------------+----+----------+---------------+--------------+------------+--------------+------------+
指定异常检测的预测间隔¶
您可以使用不同的灵敏度来检测异常。若要指定要分类为异常的观测值的百分比,请创建一个包含 <model_name>!DETECT_ANOMALIES 配置设置的 OBJECT,并将 prediction_interval
键设置为应标记为异常的观测值的百分比。
若要构造此对象,可以使用 对象常量 或 OBJECT_CONSTRUCT 函数。
然后,在调用 <model_name>!DETECT_ANOMALIES 方法时,将此对象作为 CONFIG_OBJECT 实参传入。
默认情况下,与 prediction_interval 键关联的值设置为 0.99,这意味着大约 1% 的数据会被标记为异常。您可以指定一个介于 0 和 1 之间的值:
要将较少的观测值标记为异常,请为
prediction_interval
指定更高的值。要将更多观测值标记为异常,请减小
prediction_interval
值。
以下示例通过将 prediction_interval
设置为 0.995 来配置更为严格的异常检测。该示例还使用利用标记数据训练的模型(您在 使用标记数据训练异常检测模型 中设置),以及包含要分析的数据的视图(您在 为单个时间序列检测异常(无监督) 中设置)。
CALL model_trained_with_labeled_data!DETECT_ANOMALIES(
INPUT_DATA => SYSTEM$REFERENCE('VIEW', 'view_with_data_to_analyze'),
TIMESTAMP_COLNAME => 'date',
TARGET_COLNAME => 'sales',
CONFIG_OBJECT => {'prediction_interval':0.995}
);
此语句会生成一个表,其中包含视图 view_with_data_to_analyze
中当前数据的行。每行都包含一列,其中显示检测器的预测。您可以看到,此模型的结果比未标记的示例更准确。
输出
为了便于阅读,对结果进行了四舍五入。
+--------+-------------------------+----+----------+---------------+--------------+------------+--------------+------------+
| SERIES | TS | Y | FORECAST | LOWER_BOUND | UPPER_BOUND | IS_ANOMALY | PERCENTILE | DISTANCE |
+--------|-------------------------+----+----------+---------------+--------------+------------+--------------+------------|
| NULL | 2020-01-16 00:00:00.000 | 6 | 6 | 0.36 | 11.64 | False | 0.5 | 0 |
| NULL | 2020-01-17 00:00:00.000 | 20 | 6 | -0.90 | 12.90 | True | 0.99 | 5.70 |
+--------+-------------------------+----+----------+---------------+--------------+------------+--------------+------------+
包括用于分析的其他列¶
您可以在用于训练和分析的数据中包含其他列(例如,temperature
、weather
、is_black_friday
),如果这些列可以帮助您改进对真实异常的识别。
要包含用于分析的新列,请执行以下操作:
对于训练数据,请创建包含新列的视图或设计包含新列的查询,并创建新的异常检测对象,传入对该视图或查询的引用。
对于要分析的数据,请创建包含新列的视图,或者设计包含新列的查询,并将对该视图或查询的引用传递给 <model_name>!DETECT_ANOMALIES 方法。
异常检测模型会自动检测并使用其他列。
备注
在执行 CREATE SNOWFLAKE.ML.ANOMALY_DETECTION 命令和调用 <model_name>!DETECT_ANOMALIES 方法时,必须提供具有同一组附加列的视图或查询。如果传递给命令的训练数据中的列与传递给函数的分析数据中的列不匹配,则会发生错误。
例如,假设您要添加列 temperature
、humidity
和 holiday
:
创建视图或设计查询,以返回包含这些附加列的训练数据。
对于此示例,请执行 CREATE VIEW 命令以创建名为
view_with_training_data_extra_columns
的视图:CREATE OR REPLACE VIEW view_with_training_data_extra_columns AS SELECT date, sales, label, temperature, humidity, holiday FROM historical_sales_data WHERE store_id=1 AND item='jacket';
为异常检测模型创建一个对象,利用该视图中的数据训练模型。
对于此示例,请执行 CREATE SNOWFLAKE.ML.ANOMALY_DETECTION 命令以创建名为
model_with_additional_columns
的异常检测对象,并传入对新视图的引用:CREATE OR REPLACE SNOWFLAKE.ML.ANOMALY_DETECTION model_with_additional_columns( INPUT_DATA => SYSTEM$REFERENCE('VIEW', 'view_with_training_data_extra_columns'), TIMESTAMP_COLNAME => 'date', TARGET_COLNAME => 'sales', LABEL_COLNAME => 'label' );
创建视图或设计查询以返回要使用这些附加列进行分析的数据。
对于此示例,请执行 CREATE VIEW 命令以创建名为
view_with_data_for_analysis_extra_columns
的视图:CREATE OR REPLACE VIEW view_with_data_for_analysis_extra_columns AS SELECT date, sales, temperature, humidity, holiday FROM new_sales_data WHERE store_id=1 AND item='jacket';
使用此新的异常检测对象,调用 <model_name>!DETECT_ANOMALIES 方法,传入新视图:
CALL model_with_additional_columns!DETECT_ANOMALIES( INPUT_DATA => SYSTEM$REFERENCE('VIEW', 'view_with_data_for_analysis_extra_columns'), TIMESTAMP_COLNAME => 'date', TARGET_COLNAME => 'sales', CONFIG_OBJECT => {'prediction_interval':0.93} );
此语句会生成一个表,其中包含视图
view_with_data_for_analysis_extra_columns
中当前数据的行以及检测器的预测。输出的格式与之前运行的命令显示的输出格式相同。
输出
为了便于阅读,对结果进行了四舍五入。
+--------+-------------------------+----+----------+-------------+--------------+------------+--------------+------------+ | SERIES | TS | Y | FORECAST | LOWER_BOUND | UPPER_BOUND | IS_ANOMALY | PERCENTILE | DISTANCE | +--------|-------------------------+----+----------+-------------+--------------+------------+--------------+------------| | NULL | 2020-01-16 00:00:00.000 | 6 | 6 | 2.34 | 9.64 | False | 0.5 | 0 | | NULL | 2020-01-17 00:00:00.000 | 20 | 6 | 1.56 | 10.451 | True | 0.99 | 5.70 | +--------+-------------------------+----+----------+-------------+--------------+------------+--------------+------------+
检测多个序列中的异常¶
前面的部分提供了检测单个序列异常的示例。这些示例标记了在一家商店(商店 ID 1)中,一种类型的商品(夹克)的销售异常情况。要同时为多个时间序列检测异常(例如,商品和商店的多个组合)检测异常,请执行以下操作:
对于训练数据,请创建包含新列的视图或设计包含新列的查询,并创建一个新的异常检测对象,传入对该视图或查询的引用,并为 SERIES_COLNAME 实参指定序列列的名称。
对于要分析的数据,请创建一个视图,或者设计一个查询,在其中包含识别序列的列的视图。调用 <model_name>!DETECT_ANOMALIES 方法,传入对该视图或查询的引用,并为 SERIES_COLNAME 实参指定序列列的名称。
例如,假设您要使用 store_id
和 item
列的组合来识别序列:
创建视图或设计查询以返回包含序列列的训练数据。
对于此示例,请执行 CREATE VIEW 命令以创建一个名为
view_with_training_data_multiple_series
的视图,其中包含一个名为store_item
的列,该列将序列识别为商店 ID 和商品的组合:CREATE OR REPLACE VIEW view_with_training_data_multiple_series AS SELECT [store_id, item] AS store_item, date, sales, label, temperature, humidity, holiday FROM historical_sales_data;
创建异常检测对象,并使用该视图中的数据训练模型。
对于此示例,执行 CREATE SNOWFLAKE.ML.ANOMALY_DETECTION 命令以创建名为
model_for_multiple_series
的异常检测对象,传入对新视图的引用并为 SERIES_COLNAME 实参指定store_item
:CREATE OR REPLACE SNOWFLAKE.ML.ANOMALY_DETECTION model_for_multiple_series( INPUT_DATA => SYSTEM$REFERENCE('VIEW', 'view_with_training_data_multiple_series'), SERIES_COLNAME => 'store_item', TIMESTAMP_COLNAME => 'date', TARGET_COLNAME => 'sales', LABEL_COLNAME => 'label' );
创建视图或设计查询,以返回要使用序列列进行分析的数据。
对于此示例,请执行 CREATE VIEW 命令以创建一个名为
view_with_data_for_analysis_multiple_series
的视图,其中包含名称为store_item
的序列列:CREATE OR REPLACE VIEW view_with_data_for_analysis_multiple_series AS SELECT [store_id, item] AS store_item, date, sales, temperature, humidity, holiday FROM new_sales_data;
使用此新的异常检测对象,调用 <model_name>!DETECT_ANOMALIES 方法,传入新视图并为 SERIES_COLNAME 实参指定
store_item
:CALL model_for_multiple_series!DETECT_ANOMALIES( INPUT_DATA => SYSTEM$REFERENCE('VIEW', 'view_with_data_for_analysis_multiple_series'), SERIES_COLNAME => 'store_item', TIMESTAMP_COLNAME => 'date', TARGET_COLNAME => 'sales', CONFIG_OBJECT => {'prediction_interval':0.995} );
此语句会生成一个表,其中包含视图
view_with_data_for_analysis_multiple_series
中当前数据的行以及检测器的预测。输出包括识别序列的列。
输出
为了便于阅读,对结果进行了四舍五入。
+--------------+-------------------------+----+----------+---------------+--------------+------------+---------------+--------------+ | SERIES | TS | Y | FORECAST | LOWER_BOUND | UPPER_BOUND | IS_ANOMALY | PERCENTILE | DISTANCE | |--------------+-------------------------+----+----------+---------------+--------------+------------+---------------+--------------| | [ | 2020-01-16 00:00:00.000 | 3 | 6.3 | 2.07 | 10.53 | False | 0.01 | -2.19 | | 2, | | | | | | | | | | "umbrella" | | | | | | | | | | ] | | | | | | | | | | [ | 2020-01-17 00:00:00.000 | 70 | 2.9 | -1.33 | 7.13 | True | 1 | 44.54 | | 2, | | | | | | | | | | "umbrella" | | | | | | | | | | ] | | | | | | | | | | [ | 2020-01-16 00:00:00.000 | 6 | 6 | 0.36 | 11.64 | False | 0.5 | 0 | | 1, | | | | | | | | | | "jacket" | | | | | | | | | | ] | | | | | | | | | | [ | 2020-01-17 00:00:00.000 | 20 | 6 | -0.90 | 12.90 | True | 0.99 | 5.70 | | 1, | | | | | | | | | | "jacket" | | | | | | | | | | ] | | | | | | | | | +--------------+-------------------------+----+----------+---------------+--------------+------------+---------------+--------------+
可视化异常并解释结果¶
使用 Snowsight 查看并可视化异常检测。在 Snowsight 中调用 <model_name>!DETECT_ANOMALIES 方法时,结果将显示在工作表下的表中。
要可视化结果,可使用 Snowsight 中的图表功能。
调用 <model_name>!DETECT_ANOMALIES 方法后,选择结果表上方的 Charts。
在图表右侧的 Data 部分中:
选择 Y 列,然后在 Aggregation 下方选择 None。
选择 TS 列,然后在 Bucketing 下方选择 None。
添加 LOWER_BOUND 和 UPPER_BOUND 列,然后在 Aggregation 下方选择 None。
要显示初始可视化效果,请选择 Chart。
在页面右侧选择 Add Column,然后选择要可视化的列:
LOWER_BOUND
UPPER_BOUND
IS_ANOMALY
结果:
将鼠标悬停在峰值位置,可看到 Y 超出了上限,并且在 IS_ANOMALY 字段中标记为 1。
小技巧
要更好地了解您的结果,请尝试使用 Contribution Explorer。
通过 Snowflake 任务和警报自动进行异常检测¶
通过使用 Snowflake 任务或警报中的异常检测功能,可以创建自动异常检测管道,用于重新训练模型和监控数据中的异常情况。
使用 Snowflake 任务进行重复训练¶
您可以使用 Snowflake 任务 更新模型以反映最新数据。
若要创建每小时刷新一次异常检测对象的任务,请运行以下语句,并将 your_warehouse_name
替换为您的仓库名称:
CREATE OR REPLACE TASK ad_model_retrain_task
WAREHOUSE = <your_warehouse_name>
SCHEDULE = '60 MINUTE'
AS
EXECUTE IMMEDIATE
$$
BEGIN
CREATE OR REPLACE SNOWFLAKE.ML.ANOMALY_DETECTION model_trained_with_labeled_data(
INPUT_DATA => SYSTEM$REFERENCE('VIEW', 'view_with_labeled_data_for_training'),
TIMESTAMP_COLNAME => 'date',
TARGET_COLNAME => 'sales',
LABEL_COLNAME => 'label'
);
END;
$$;
新创建的任务默认处于暂停状态。
要继续任务,请执行 ALTER TASK ...RESUME 命令:
ALTER TASK ad_model_retrain_task RESUME;
要暂停任务,请执行 ALTER TASK ...SUSPEND 命令:
ALTER TASK ad_model_retrain_task SUSPEND;
使用 Snowflake Task 进行监控¶
您还可以使用 Snowflake 任务以给定频率监控数据。
首先,创建表来保存异常检测结果:
CREATE OR REPLACE TABLE anomaly_res_table (
ts TIMESTAMP_NTZ, y FLOAT, forecast FLOAT, lower_bound FLOAT, upper_bound FLOAT,
is_anomaly BOOLEAN, percentile FLOAT, distance FLOAT);
创建任务,在表中存储定期异常检测操作的结果。本示例将 WAREHOUSE
参数设置为 snowhouse
。您可以将其替换为自己的仓库:
CREATE OR REPLACE TASK ad_model_monitoring_task
WAREHOUSE = snowhouse
SCHEDULE = '1 minute'
AS
EXECUTE IMMEDIATE
$$
BEGIN
CALL model_trained_with_labeled_data!DETECT_ANOMALIES(
INPUT_DATA => SYSTEM$REFERENCE('VIEW', 'view_with_data_to_analyze'),
TIMESTAMP_COLNAME => 'date',
TARGET_COLNAME => 'sales',
CONFIG_OBJECT => {'prediction_interval':0.99}
);
INSERT INTO anomaly_res_table (ts, y, forecast, lower_bound, upper_bound, is_anomaly, percentile, distance)
SELECT * FROM TABLE(RESULT_SCAN(LAST_QUERY_ID()));
END;
$$;
要继续任务,请执行 ALTER TASK ...RESUME 命令:
ALTER TASK ad_model_monitoring_task RESUME;
然后,anomaly_res_table
将包含每次任务运行的所有结果。
要暂停任务,请执行 ALTER TASK ...SUSPEND 命令:
ALTER TASK ad_model_monitoring_task SUSPEND;
使用 Snowflake 警报进行监控¶
您还可以使用 Snowflake 警报 以给定频率监控数据,并向您发送包含检测到的异常的电子邮件。以下语句创建每分钟检测一次异常的警报。首先定义一个 存储过程 来检测异常,然后创建使用该存储过程的警报。
备注
必须设置电子邮件集成才能通过存储过程发送邮件;请参阅 Snowflake 中的通知。
CREATE OR REPLACE PROCEDURE extract_anomalies()
RETURNS TABLE()
LANGUAGE SQL
AS
$$
BEGIN
CALL model_trained_with_labeled_data!DETECT_ANOMALIES(
INPUT_DATA => SYSTEM$REFERENCE('VIEW', 'view_with_data_to_analyze'),
TIMESTAMP_COLNAME => 'date',
TARGET_COLNAME => 'sales',
CONFIG_OBJECT => {'prediction_interval':0.99}
);
DECLARE
res RESULTSET DEFAULT (SELECT * FROM TABLE(RESULT_SCAN(-1)) WHERE is_anomaly = TRUE);
BEGIN
RETURN TABLE(res);
END;
END;
$$
;
CREATE OR REPLACE ALERT sample_sales_alert
WAREHOUSE = <your_warehouse_name>
SCHEDULE = '1 MINUTE'
IF (EXISTS (CALL extract_anomalies()))
THEN
CALL SYSTEM$SEND_EMAIL(
'sales_email_alert',
'your_email@snowflake.com',
'Anomalous Sales Data Detected in data stream',
CONCAT(
'Anomalous Sales Data Detected in data stream \n',
'Value outside of prediction interval detected in the most recent run at ',
current_timestamp(1)
));
要启动或恢复警报,请执行 ALTER ALERT ...RESUME 命令:
ALTER ALERT sample_sales_alert RESUME;
要暂停警报,请执行 ALTER ALERT ...SUSPEND 命令:
ALTER ALERT sample_sales_alert SUSPEND;
了解特征的重要性¶
异常检测模型可以解释模型中使用的所有特征的相对重要性,包括您选择的任何外生变量、自动生成的时间特征(例如星期几或一年中的某周)以及目标变量(例如滚动平均值和自动回归滞后)的转换。这些信息有助于了解真正影响数据的要素。
<model_name>!EXPLAIN_FEATURE_IMPORTANCE 方法会计算模型树使用每个特征做出决策的次数。然后将这些特征重要性得分归一化为 0 到 1 之间的值,它们的总和是 1。生成的分数表示训练模型中特征的近似排名。
得分接近的特征具有相似的重要性。对于极其简单的序列(例如,目标列的值为常数),所有特征重要性得分可能为零。
使用彼此非常相似的多个特征可能会降低这些特征的重要性得分。例如,如果一个特征是 已售商品数量,另一个特征是 库存商品数量,则这些值可能是相关的,因为您销售的商品不能超过您拥有的商品,并且您尝试管理库存,因此您的库存不会多于销售的库存。如果两个特征相同,则模型在做出决策时可能会将它们视为可互换的,从而导致特征重要性分数是仅包含一个特征时这些分数的一半。
特征重要性还报告 滞后特征。在训练期间,模型会推断训练数据的频率(每小时、每天或每周)。特征 lagx`(例如 :code:`lag24
)是目标变量 x 过去的时间单位得出的值。例如,如果每小时推断一次数据,则 lag24
表示 24 小时前的目标变量。
目标变量(滚动平均值等)的所有其他转换在结果表中汇总为 aggregated_endogenous_features
。
限制¶
不能选择用于计算特征重要性的技术。
特征重要性分数有助于直观地了解哪些特征对模型的准确性较为重要,但应将实际值视为估计值。
示例¶
若要了解特征对模型的相对重要性,请训练模型,然后调用 <model_name>!EXPLAIN_FEATURE_IMPORTANCE。在此示例中,您首先使用两个外生变量创建随机数据:一个是随机的,因此不太可能对模型非常重要,另一个是目标的副本,因此可能对模型更重要。
执行以下语句以生成数据,利用其训练模型,并获取特征的重要性:
CREATE OR REPLACE VIEW v_random_data AS SELECT
DATEADD('minute', ROW_NUMBER() over (ORDER BY 1), '2023-12-01')::TIMESTAMP_NTZ ts,
MOD(SEQ1(),10) y,
UNIFORM(1, 100, RANDOM(0)) exog_a
FROM TABLE(GENERATOR(ROWCOUNT => 500));
CREATE OR REPLACE VIEW v_feature_importance_demo AS SELECT
ts,
y,
exog_a
FROM v_random_data;
SELECT * FROM v_feature_importance_demo;
CREATE OR REPLACE SNOWFLAKE.ML.ANOMALY_DETECTION anomaly_model_feature_importance_demo(
INPUT_DATA => SYSTEM$REFERENCE('VIEW', 'v_feature_importance_demo'),
TIMESTAMP_COLNAME => 'ts',
TARGET_COLNAME => 'y',
LABEL_COLNAME => ''
);
CALL anomaly_model_feature_importance_demo!EXPLAIN_FEATURE_IMPORTANCE();
输出
由于此示例使用随机数据,因此不要期望输出与此数据完全匹配。
+--------+------+--------------------------------------+-------+-------------------------+
| SERIES | RANK | FEATURE_NAME | SCORE | FEATURE_TYPE |
+--------+------+--------------------------------------+-------+-------------------------+
| NULL | 1 | aggregated_endogenous_trend_features | 0.36 | derived_from_endogenous |
| NULL | 2 | exog_a | 0.22 | user_provided |
| NULL | 3 | epoch_time | 0.15 | derived_from_timestamp |
| NULL | 4 | minute | 0.13 | derived_from_timestamp |
| NULL | 5 | lag60 | 0.07 | derived_from_endogenous |
| NULL | 6 | lag120 | 0.06 | derived_from_endogenous |
| NULL | 7 | hour | 0.01 | derived_from_timestamp |
+--------+------+--------------------------------------+-------+-------------------------+
检查训练日志¶
使用 CONFIG_OBJECT => 'ON_ERROR': 'SKIP'
训练多个序列时,单个时间序列模型可能训练失败,但整个训练过程不会失败。要了解哪个时间序列失败以及失败的原因,请调用 <model_instance>!SHOW_TRAINING_LOGS
。
示例¶
CREATE TABLE t_error(date TIMESTAMP_NTZ, sales FLOAT, series VARCHAR);
INSERT INTO t_error VALUES
(TO_TIMESTAMP_NTZ('2019-12-20'), 1.0, 'A'),
(TO_TIMESTAMP_NTZ('2019-12-21'), 2.0, 'A'),
(TO_TIMESTAMP_NTZ('2019-12-22'), 3.0, 'A'),
(TO_TIMESTAMP_NTZ('2019-12-23'), 2.0, 'A'),
(TO_TIMESTAMP_NTZ('2019-12-24'), 1.0, 'A'),
(TO_TIMESTAMP_NTZ('2019-12-25'), 2.0, 'A'),
(TO_TIMESTAMP_NTZ('2019-12-26'), 3.0, 'A'),
(TO_TIMESTAMP_NTZ('2019-12-27'), 2.0, 'A'),
(TO_TIMESTAMP_NTZ('2019-12-28'), 1.0, 'A'),
(TO_TIMESTAMP_NTZ('2019-12-29'), 2.0, 'A'),
(TO_TIMESTAMP_NTZ('2019-12-30'), 3.0, 'A'),
(TO_TIMESTAMP_NTZ('2019-12-31'), 2.0, 'A'),
(TO_TIMESTAMP_NTZ('2020-01-01'), 2.0, 'A'),
(TO_TIMESTAMP_NTZ('2020-01-02'), 3.0, 'A'),
(TO_TIMESTAMP_NTZ('2020-01-03'), 3.0, 'A'),
(TO_TIMESTAMP_NTZ('2020-01-04'), 7.0, 'A'),
(TO_TIMESTAMP_NTZ('2020-01-05'), 10.0, 'B'),
(TO_TIMESTAMP_NTZ('2020-01-06'), 13.0, 'B'),
(TO_TIMESTAMP_NTZ('2020-01-06'), 12.0, 'B'), -- duplicate timestamp
(TO_TIMESTAMP_NTZ('2020-01-07'), 15.0, 'B'),
(TO_TIMESTAMP_NTZ('2020-01-08'), 14.0, 'B'),
(TO_TIMESTAMP_NTZ('2020-01-09'), 18.0, 'B'),
(TO_TIMESTAMP_NTZ('2020-01-10'), 12.0, 'B');
CREATE SNOWFLAKE.ML.ANOMALY_DETECTION model(
INPUT_DATA => SYSTEM$QUERY_REFERENCE('SELECT date, sales, series FROM t_error'),
SERIES_COLNAME => 'series',
TIMESTAMP_COLNAME => 'date',
TARGET_COLNAME => 'sales',
LABEL_COLNAME => '',
CONFIG_OBJECT => {'ON_ERROR': 'SKIP'}
);
CALL model!SHOW_TRAINING_LOGS();
输出
+--------+-------------------------------------------------------------------------------------------------+
| SERIES | LOGS |
+--------+-------------------------------------------------------------------------------------------------+
| "B" | { "Errors": [ "Frequency cannot be inferred when duplicate timestamps are present." ] } |
| "A" | NULL |
+--------+-------------------------------------------------------------------------------------------------+
成本注意事项¶
训练和使用异常检测模型会产生存储和计算成本。
如 选择虚拟仓库 中所述,训练消耗的计算量多于已训练模型的预测量。但是,重复使用后,预测的成本可能会增加。 有关 Snowflake 计算成本的一般信息,请参阅 了解计算成本。
您产生的存储成本反映了在训练步骤中创建的 ML 模型实例占用的存储空间。要查看与模型实例关联的对象,请导航到 Account Usage 视图(例如,ACCOUNT_USAGE.TABLES 和 ACCOUNT_USAGE.STAGES)。这些对象将显示为 NULL 数据库和架构列。但 instance_id
列将会填充,并指示这些对象包含在模型实例内。这些对象完全由模型实例管理,您无法单独访问或删除。要降低与模型相关的存储成本,请删除未使用或过时的模型。
在 Snowpark 中使用异常检测¶
session.call
尚与异常检测模型不兼容。要在 Snowpark 中调用异常检测模型,请改用 session.sql
,如下所示。
session.sql('call my_model!detect_anomalies(...)').collect()