时间序列预测(Snowflake Cortex ML 函数)

备注

预测是 Snowflake 的智能、完全托管的 AI 和 ML 服务,是 Snowflake Cortex 的一部分。此功能是 Snowflake Cortex ML 函数套件的一部分。

预测采用机器学习算法,利用历史时间序列数据预测未来数据。时间序列预测根据历史输入数据对未来数据进行单变量预测。常见的用例是根据季节性和其他因素预测销售额。

历史数据必须包括:

  • 时间戳列,该列应具有固定频率(例如每小时、每 5 分钟等)。

  • 目标列,代表每个时间戳下的某些相关数量。

历史数据还可以包括可能影响目标的其他列(外生变量 (link removed))。这些列可以是数字或字符数据。

历史数据用于训练机器学习模型,该模型可对未来时间戳下的目标值进行预测。该模型是架构级对象,训练完成后可用于多个预测。(该模型不能用于生成与历史数据处于同一范围的预测。)

预测适用于单序列或多序列数据。多序列数据表示事件的多个不同线程。例如,如果存在多个商店的销售数据,则可以根据商店标识符通过单个模型单独预测每个商店的销售额。

要生成时间序列数据的预测,请使用 Snowflake 内置类 FORECAST (SNOWFLAKE.ML),然后执行以下步骤:

  1. 创建一个预测模型对象,传入对训练数据的引用。此对象会根据您提供的训练数据拟合(训练)模型。该模型是一个架构级对象。

  2. 通过使用此预测模型对象,调用 预测方法 来生成未来时间戳的目标预测,并传入时间步长数或未来值的外生数据(如果使用外生变量)。

重要

法律声明。 此 Snowflake Cortex ML 函数由机器学习技术提供支持。机器学习技术和提供的结果可能不准确、不合适或较为片面。基于机器学习输出(包括内置在自动管道中的输出)的决策应有人工监督和审查流程,以确保模型生成的内容准确无误。Snowflake Cortex ML 函数查询将被视为任何其他 SQL 查询,并可能被视为 元数据

元数据。 当您使用 Snowflake Cortex ML 函数时,除了 元数据字段 中提及的内容外,Snowflake 还会记录 ML 函数返回的通用错误消息。这些错误日志可帮助我们排查出现的问题,并改进这些函数以更好地满足您的需求。

有关更多信息,请参阅 Snowflake AI 信任与安全 FAQ

关于预测算法

预测算法由 梯度提升机 (link removed) (GBM) 提供支持。与 ARIMA (link removed) 模型一样,它使用差分变换对具有非平稳趋势的数据进行建模,并使用历史目标数据的自回归滞后项作为模型变量。

此外,该算法使用历史目标数据的滚动平均值来帮助预测趋势,并使用时间戳数据自动生成循环日历变量(例如星期几和一年中的一周)。

您可以仅使用历史目标值和时间戳数据拟合模型,也可以加入可能影响目标值的外生数据(变量)。外生变量可以是数值或分类值,也可以是 NULL(不会删除包含 NULLs 外生变量的行)。

在对分类变量进行训练时,该算法不依赖单次编码,因此可以使用多维度(高基数)的分类数据。

如果模型包含外生变量,则在生成预测时,必须在整个预测范围的每个时间戳处为这些变量提供值。适当的外生变量包括天气数据(温度、降雨量)、公司特定信息(历史和计划的公司假期、广告活动、活动时间表),或者您认为可能有助于预测目标变量的任何其他外部因素。

除了预测之外,此算法还可生成预测区间。预测区间是上限和下限内的估计值范围,一定百分比的数据可能会落在这个范围内。例如,值 0.95 表示 95% 的数据可能出现在区间内。您可以指定预测区间百分比,或使用默认值 0.95。预测区间的下限和上限将作为预测输出的一部分返回。

重要

Snowflake 会不时完善预测算法,并将通过定期 Snowflake 发布过程推出此类改进。您无法恢复到该功能的先前版本,但使用先前版本创建的模型将继续使用该版本进行预测。

当前限制

当前版本具有以下限制:

  • 您无法选择或调整预测算法。

  • 主要预测算法的最小行数为每个时间序列 12 行。对于观测值介于 2 到 11 个之间的时间序列,预测会产生一个“朴素”的预测,其中所有预测值都等于上次观测的目标值。

  • 预测函数不提供替换趋势、季节性或季节性幅度的参数;这些参数是从数据推断出来的。

  • 可接受的最小数据粒度为一秒。(时间戳之间的间隔不得短于一秒。)

  • 季节性组件的最小精确度为 1 分钟。(函数无法在较小时间增量下检测到循环模式。)

  • 数据中的时间戳必须表示固定的时间间隔。如果输入数据不规则,请在训练模型时尝试在时间戳列上使用 DATE_TRUNCTIME_SLICE

  • 自回归特征的“季节长度”与输入频率相关联(每小时数据为 24,每日数据为 7,依此类推)。

  • 预测模型一旦经过训练,就是不可变的。您不能使用新数据更新现有模型;您必须训练一个全新模型。模型不支持版本控制。Snowflake 建议根据您接收新数据的频率,定期(可能是每天、每周或每月)重新训练模型,使模型能够适应不断变化的模式和趋势。

  • 您无法克隆模型或跨角色或账户共享模型。 克隆架构或数据库时,将会跳过模型对象。

  • 您不能 复制 FORECAST 类的实例。

准备预测

在使用预测之前,您必须执行以下操作:

您可能还想 修改搜索路径 以包含 SNOWFLAKE.ML。

选择虚拟仓库

Snowflake 虚拟仓库 为该功能提供训练和使用机器学习模型所需的计算资源。本节提供有关为此目的选择最佳类型和大小的仓库的一般指导,重点介绍培训步骤,该过程中最耗时、最耗费内存的部分。

单序列数据训练

对于基于单序列数据训练的模型,应根据训练数据的大小选择仓库类型。标准仓库的 Snowpark 内存限制 较低,更适合行数和外生变量较少的训练作业。

如果训练数据不包含任何外生变量,数据集的行数不超过 500 万行,就可以基于标准仓库进行训练。如果训练数据使用 5 个或更多外生变量,则最大行数会更少。否则,Snowflake 建议使用 Snowpark 优化型仓库 完成更大规模的训练作业。

一般来说,对于单序列数据,仓库规模越大,训练时间越短,内存限制也越高。粗略的经验法则是,训练时间与时间序列的行数成正比。例如,在 XS 标准仓库上,对 100,000 行数据集进行训练大约需要 30 秒。在 1,000,000 行数据集上进行训练大约需要 140 秒。

为了获得最佳性能,Snowflake 建议使用没有其他并发工作负载的专用仓库来训练模型。

多序列数据训练

与单序列数据一样,Snowflake 建议根据最大时间序列中的行数选择仓库类型。如果最大时间序列包含的行数超过 500 万行,则训练作业可能会超出标准仓库的内存限制。

与单系列数据不同,多系列数据在较大的仓库规模上训练速度要快得多。以下数据点可以指导您进行选择。

仓库类型

时间序列数

每个时间序列的行数

仓库规模

训练时间

标准型

1

100,000

XS

38 秒

10

100,000

XS

112 秒

100

100,000

XS

594 秒

10

100,000

XL

34 秒

100

100,000

XL

114 秒

1000

100,000

XL

572 秒

Snowpark-optimized

10

100,000

XL

74 秒

100

100,000

XL

215 秒

1000

100,000

XL

1429 秒

授予创建预测对象的权限

训练预测模型会生成架构级对象。因此,用于创建模型的角色必须对创建模型的架构具有 CREATE SNOWFLAKE.ML.FORECAST 权限,这样才能将模型存储在该架构中。此权限类似于其他架构权限,如 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.FORECAST ON SCHEMA admin_db.admin_schema TO ROLE analyst;
Copy

要使用此架构,用户将承担 analyst 角色:

USE ROLE analyst;
USE SCHEMA admin_db.admin_schema;
Copy

如果 analyst 角色在数据库 analyst_db 中具有 CREATE SCHEMA 权限,则该角色可以创建新架构 analyst_db.analyst_schema 并在该架构中创建预测模型:

USE ROLE analyst;
CREATE SCHEMA analyst_db.analyst_schema;
USE SCHEMA analyst_db.analyst_schema;
Copy

要撤消角色对架构的预测模型创建权限,请使用 REVOKE <privileges>

REVOKE CREATE SNOWFLAKE.ML.FORECAST ON SCHEMA admin_db.admin_schema FROM ROLE analyst;
Copy

为示例设置数据

下面的示例创建了两个表。这些表的视图包含在本主题后面的 示例 中。

sales_data 表包含销售数据。每笔销售包括一个商店 ID、一个项目标识符、一个时间戳和销售金额。此外,还包括外生变量或外部变量(温度、湿度和节假日)。

future_features 表包含外生变量的未来值,在使用此类变量进行预测时,这些值是必需的。

CREATE OR REPLACE TABLE sales_data (store_id NUMBER, item VARCHAR, date TIMESTAMP_NTZ,
  sales FLOAT, temperature NUMBER, humidity FLOAT, holiday VARCHAR);

INSERT INTO sales_data VALUES
  (1, 'jacket', TO_TIMESTAMP_NTZ('2020-01-01'), 2.0, 50, 0.3, 'new year'),
  (1, 'jacket', TO_TIMESTAMP_NTZ('2020-01-02'), 3.0, 52, 0.3, NULL),
  (1, 'jacket', TO_TIMESTAMP_NTZ('2020-01-03'), 4.0, 54, 0.2, NULL),
  (1, 'jacket', TO_TIMESTAMP_NTZ('2020-01-04'), 5.0, 54, 0.3, NULL),
  (1, 'jacket', TO_TIMESTAMP_NTZ('2020-01-05'), 6.0, 55, 0.2, NULL),
  (1, 'jacket', TO_TIMESTAMP_NTZ('2020-01-06'), 7.0, 55, 0.2, NULL),
  (1, 'jacket', TO_TIMESTAMP_NTZ('2020-01-07'), 8.0, 55, 0.2, NULL),
  (1, 'jacket', TO_TIMESTAMP_NTZ('2020-01-08'), 9.0, 55, 0.2, NULL),
  (1, 'jacket', TO_TIMESTAMP_NTZ('2020-01-09'), 10.0, 55, 0.2, NULL),
  (1, 'jacket', TO_TIMESTAMP_NTZ('2020-01-10'), 11.0, 55, 0.2, NULL),
  (1, 'jacket', TO_TIMESTAMP_NTZ('2020-01-11'), 12.0, 55, 0.2, NULL),
  (1, 'jacket', TO_TIMESTAMP_NTZ('2020-01-12'), 13.0, 55, 0.2, NULL),
  (2, 'umbrella', TO_TIMESTAMP_NTZ('2020-01-01'), 2.0, 50, 0.3, 'new year'),
  (2, 'umbrella', TO_TIMESTAMP_NTZ('2020-01-02'), 3.0, 52, 0.3, NULL),
  (2, 'umbrella', TO_TIMESTAMP_NTZ('2020-01-03'), 4.0, 54, 0.2, NULL),
  (2, 'umbrella', TO_TIMESTAMP_NTZ('2020-01-04'), 5.0, 54, 0.3, NULL),
  (2, 'umbrella', TO_TIMESTAMP_NTZ('2020-01-05'), 6.0, 55, 0.2, NULL),
  (2, 'umbrella', TO_TIMESTAMP_NTZ('2020-01-06'), 7.0, 55, 0.2, NULL),
  (2, 'umbrella', TO_TIMESTAMP_NTZ('2020-01-07'), 8.0, 55, 0.2, NULL),
  (2, 'umbrella', TO_TIMESTAMP_NTZ('2020-01-08'), 9.0, 55, 0.2, NULL),
  (2, 'umbrella', TO_TIMESTAMP_NTZ('2020-01-09'), 10.0, 55, 0.2, NULL),
  (2, 'umbrella', TO_TIMESTAMP_NTZ('2020-01-10'), 11.0, 55, 0.2, NULL),
  (2, 'umbrella', TO_TIMESTAMP_NTZ('2020-01-11'), 12.0, 55, 0.2, NULL),
  (2, 'umbrella', TO_TIMESTAMP_NTZ('2020-01-12'), 13.0, 55, 0.2, NULL);

-- future values for exogenous variables (additional features)
CREATE OR REPLACE TABLE future_features (store_id NUMBER, item VARCHAR,
  date TIMESTAMP_NTZ, temperature NUMBER, humidity FLOAT, holiday VARCHAR);

INSERT INTO future_features VALUES
  (1, 'jacket', TO_TIMESTAMP_NTZ('2020-01-13'), 52, 0.3, NULL),
  (1, 'jacket', TO_TIMESTAMP_NTZ('2020-01-14'), 53, 0.3, NULL),
  (2, 'umbrella', TO_TIMESTAMP_NTZ('2020-01-13'), 52, 0.3, NULL),
  (2, 'umbrella', TO_TIMESTAMP_NTZ('2020-01-14'), 53, 0.3, NULL);
Copy

训练、使用、查看、删除和更新模型

使用 CREATE SNOWFLAKE.ML.FORECAST 创建和训练模型。模型是在您提供的数据集上训练的。

CREATE SNOWFLAKE.ML.FORECAST <name>(...);
Copy

有关 SNOWFLAKE.ML.FORECAST 构造函数的完整详细信息,请参阅 FORECAST (SNOWFLAKE.ML)。有关创建模型的示例,请参阅 示例

备注

SNOWFLAKE.ML.FORECAST 使用有限的权限运行,因此默认情况下它无权访问数据。因此,您必须将表和视图作为 引用 传递,以便传递调用方的权限。还可以提供 查询引用, 而不是对表或视图的引用。

要生成预测,请调用模型的 <model_name>!FORECAST 方法:

CALL <name>!FORECAST(...)
Copy

要查看模型列表,请使用 SHOW SNOWFLAKE.ML.FORECAST 命令:

SHOW SNOWFLAKE.ML.FORECAST;
Copy

要移除模型,请使用 DROP SNOWFLAKE.ML.FORECAST 命令:

DROP SNOWFLAKE.ML.FORECAST <name>;
Copy

要更新模型,请将其删除并训练新模型。 模型是不可变的,不能就地更新。

生成预测

创建模型后,可以使用 name!FORECAST(...) 生成预测。您可以使用同一模型从多个数据集创建预测。

以下示例演示了如何创建模型并从中生成预测;有关所有参数的详细信息,请参阅 <model_name>!FORECAST

小技巧

要在列名与用于训练模型的数据集不同的数据集中使用模型,请创建一个视图或查询,(使用 AS)将列重命名为模型所需的名称。使用该视图或查询作为 FORECAST 方法的输入。

有关创建和使用模型时使用的参数的信息,请参阅 FORECAST (SNOWFLAKE.ML)

示例

下面的示例演示了在各种情况下如何使用时间序列预测。

对单个序列进行预测

此示例使用的是单个时间序列(即所有行都是单个序列的一部分),该序列具有两列(时间戳列和目标值列),没有其他功能。首先,将 sales_data 的数据集准备就绪以训练模型。下面的代码可创一个建名为 v1 的视图:

CREATE OR REPLACE VIEW v1 AS SELECT date, sales
  FROM sales_data WHERE store_id=1 AND item='jacket';
SELECT * FROM v1;
Copy

SELECT 语句会返回以下内容:

+-------------------------+-------+
| DATE                    | SALES |
+-------------------------+-------+
| 2020-01-01 00:00:00.000 | 2     |
| 2020-01-02 00:00:00.000 | 3     |
| 2020-01-03 00:00:00.000 | 4     |
| 2020-01-04 00:00:00.000 | 5     |
| 2020-01-05 00:00:00.000 | 6     |
+-------------------------+-------+

以下语句使用上述数据集训练预测模型。

CREATE SNOWFLAKE.ML.FORECAST model1(
  INPUT_DATA => SYSTEM$REFERENCE('VIEW', 'v1'),
  TIMESTAMP_COLNAME => 'date',
  TARGET_COLNAME => 'sales'
);
Copy

模型训练完成后,系统将显示以下消息:

Instance MODEL1 successfully created.

预测模型现在可作为 model1 使用。要预测接下来的三个时间戳,请调用以下语句:

call model1!FORECAST(FORECASTING_PERIODS => 3);
Copy

输出

请注意,该模型已根据训练数据推断出时间戳之间的间隔。

+--------+-------------------------+-----------+--------------+--------------+
| SERIES | TS                      | FORECAST  | LOWER_BOUND  | UPPER_BOUND  |
+--------+-------------------------+-----------+--------------+--------------+
| NULL   | 2020-01-13 00:00:00.000 | 14        | 14           | 14           |
| NULL   | 2020-01-14 00:00:00.000 | 15        | 15           | 15           |
| NULL   | 2020-01-15 00:00:00.000 | 16        | 16           | 16           |
+--------+-------------------------+-----------+--------------+--------------+

在本示例中,由于预测结果是完全线性的,与实际值相比误差为零,因此预测区间(LOWER_BOUND、UPPER_BOUND)与 FORECAST 值相同。

要自定义预测区间的大小,请将 prediction_interval 作为配置对象的一部分传递:

CALL model1!FORECAST(FORECASTING_PERIODS => 3, CONFIG_OBJECT => {'prediction_interval': 0.8});
Copy

若要将结果直接保存到表中,请使用以下代码:

BEGIN
  CALL model1!FORECAST(FORECASTING_PERIODS => 3);
  LET x := SQLID;
  CREATE TABLE my_forecasts AS SELECT * FROM TABLE(RESULT_SCAN(:x));
END;
SELECT * FROM my_forecasts;
Copy

尽管上面的代码使用 RESULT_SCAN,但 即使 多个进程同时运行,它也不受竞争条件的约束。上述模型调用的结果将确定性地存储到 my_forecasts 表中。

对具有外生变量的单个序列进行预测

如果希望附加特征(例如节假日或天气)影响预测,则必须在训练数据中包含这些特征。在此处,您需要创建一个视图,其中包含 sales_data 表中这些特征字段:

CREATE OR REPLACE VIEW v2 AS SELECT date, sales, temperature, humidity, holiday
  FROM sales_data WHERE store_id=1 AND item='jacket';
SELECT * FROM v2;
Copy

输出

这是 SELECT 查询结果的前五行。

+-------------------------+--------+-------------+----------+----------+
| DATE                    | SALES  | TEMPERATURE | HUMIDITY | HOLIDAY  |
+-------------------------+--------+-------------+----------+----------+
| 2020-01-01 00:00:00.000 | 2      | 50          | 0.3      | new year |
| 2020-01-02 00:00:00.000 | 3      | 52          | 0.3      | null     |
| 2020-01-03 00:00:00.000 | 4      | 54          | 0.2      | null     |
| 2020-01-04 00:00:00.000 | 5      | 54          | 0.3      | null     |
| 2020-01-05 00:00:00.000 | 6      | 55          | 0.2      | null     |
+-------------------------+--------+-------------+----------+----------+

现在,您可以使用此视图来训练模型。您只需指定时间戳和目标列名称;输入数据中的其他列会被假定为外生变量。

CREATE SNOWFLAKE.ML.FORECAST model2(
  INPUT_DATA => SYSTEM$REFERENCE('VIEW', 'v2'),
  TIMESTAMP_COLNAME => 'date',
  TARGET_COLNAME => 'sales'
);
Copy

新模型名为 model2。要对未来时间戳执行预测,则必须为模型中的外生变量提供未来值:在本例中为 TEMPERATUREHUMIDITYHOLIDAY。这样您就可以回答“假设”问题,例如“如果温度比正常温度低怎么办?”现在,基于包含未来时间戳对应数据的 future_features 表创建一个视图:

CREATE OR REPLACE VIEW v2_forecast AS select date, temperature, humidity, holiday
  FROM future_features WHERE store_id=1 AND item='jacket';
SELECT * FROM v2_forecast;
Copy

输出

+-------------------------+-------------+----------+---------+
| DATE                    | TEMPERATURE | HUMIDITY | HOLIDAY |
+-------------------------+-------------+----------+---------+
| 2020-01-13 00:00:00.000 | 52          | 0.3      | null    |
| 2020-01-14 00:00:00.000 | 53          | 0.3      | null    |
+-------------------------+-------------+----------+---------+

现在,您可以使用以下数据生成预测:

CALL model2!FORECAST(
  INPUT_DATA => SYSTEM$REFERENCE('VIEW', 'v2_forecast'),
  TIMESTAMP_COLNAME =>'date'
);
Copy

在 FORECAST 方法的这种变体中,您无需指定要预测的时间戳数量。相反,预测的时间戳来自 v2_forecast 视图。

+--------+-------------------------+-----------+--------------+--------------+
| SERIES | TS                      | FORECAST  | LOWER_BOUND  | UPPER_BOUND  |
+--------+-------------------------+-----------+--------------+--------------+
| NULL   | 2020-01-13 00:00:00.000 | 14        | 14           | 14           |
| NULL   | 2020-01-14 00:00:00.000 | 15        | 15           | 15           |
+--------+-------------------------+-----------+--------------+--------------+

多系列预测

上述预测是针对单个序列的:训练数据中的所有行都表示单一的数值序列。您还可以同时为多个序列创建预测模型。

示例数据包含 store_iditem 列。要分别预测数据集中每个商店/物品组合的销售额,可创建一个新列来组合这些值,并指定其为系列列。

例如,以下查询创建了一个新视图,该视图将 store_iditem 合并到一个名为 store_item 的新列中:

CREATE OR REPLACE VIEW v3 AS SELECT [store_id, item] AS store_item, date, sales FROM sales_data;
SELECT * FROM v3;
Copy

输出

生成的数据集的每个序列的前五行是:

+-------------------+-------------------------+-------+
| STORE_ITEM        | DATE                    | SALES |
+-------------------+-------------------------+-------+
| [ 1, "jacket" ]   | 2020-01-01 00:00:00.000 | 2     |
| [ 1, "jacket" ]   | 2020-01-02 00:00:00.000 | 3     |
| [ 1, "jacket" ]   | 2020-01-03 00:00:00.000 | 4     |
| [ 1, "jacket" ]   | 2020-01-04 00:00:00.000 | 5     |
| [ 1, "jacket" ]   | 2020-01-05 00:00:00.000 | 6     |
| [ 2, "umbrella" ] | 2020-01-01 00:00:00.000 | 2     |
| [ 2, "umbrella" ] | 2020-01-02 00:00:00.000 | 3     |
| [ 2, "umbrella" ] | 2020-01-03 00:00:00.000 | 4     |
| [ 2, "umbrella" ] | 2020-01-04 00:00:00.000 | 5     |
| [ 2, "umbrella" ] | 2020-01-05 00:00:00.000 | 6     |
+-------------------+-------------------------+-------+

以下语句使用上述数据集训练预测模型。请务必指定序列列名称,即 store_item

CREATE SNOWFLAKE.ML.FORECAST model3(
  INPUT_DATA => SYSTEM$REFERENCE('VIEW', 'v3'),
  SERIES_COLNAME => 'store_item',
  TIMESTAMP_COLNAME => 'date',
  TARGET_COLNAME => 'sales'
);
Copy

训练完成后,您可以使用以下方式同时对所有序列进行两步预测(即每个序列两个步骤):

CALL model3!FORECAST(FORECASTING_PERIODS => 2);
Copy

输出

+-------------------+------------------------+----------+-------------+-------------+
| SERIES            | TS                     | FORECAST | LOWER_BOUND | UPPER_BOUND |
+-------------------+------------------------+----------+-------------+-------------+
| [ 1, "jacket" ]   | 2020-01-13 00:00:00.000 | 14      | 14          | 14          |
| [ 1, "jacket" ]   | 2020-01-14 00:00:00.000 | 15      | 15          | 15          |
| [ 2, "umbrella" ] | 2020-01-13 00:00:00.000 | 14      | 14          | 14          |
| [ 2, "umbrella" ] | 2020-01-14 00:00:00.000 | 15      | 15          | 15          |
+-------------------+-------------------------+---------+-------------+-------------+

您还可以通过以下方式仅预测特定序列:

CALL model3!FORECAST(SERIES_VALUE => [2,'umbrella'], FORECASTING_PERIODS => 2);
Copy

输出

结果只显示了商店 2 的雨伞销售的后续两个步骤。

+-------------------+------------ ------------+-----------+-------------+-------------+
| SERIES            | TS                      | FORECAST  | LOWER_BOUND | UPPER_BOUND |
+-------------------+---------- --------------+-----------+-------------+-------------+
| [ 2, "umbrella" ] | 2020-01-13 00:00:00.000 | 14        | 14          | 14          |
| [ 2, "umbrella" ] | 2020-01-15 00:00:00.000 | 15        | 15          | 15          |
+-------------------+-------------------------+-----------+-------------+-------------+

小技巧

使用 FORECAST 方法指定一个序列比筛选多序列预测的结果以仅包含您感兴趣的序列更有效,因为这样做只会生成一个序列的预测。

对具有外生变量的多个序列进行预测

要与外生变量并行训练和预测多个时间序列,实质上是结合前两个示例,请按以下方式准备数据,同时包含一个序列列(在本例中为 store_item )和至少一个外生列(此处为 temperature ):

CREATE OR REPLACE VIEW v4 AS SELECT [store_id, item] AS store_item,
  date, sales, temperature FROM sales_data;
SELECT * FROM v4;
Copy

输出

生成的数据集的每个系列的前五行如下所示。

+-------------------+-------------------------+-------+-------------+
| STORE_ITEM        | DATE                    | SALES | TEMPERATURE |
+-------------------+-------------------------+-------+-------------+
| [ 1, "jacket" ]   | 2020-01-01 00:00:00.000 | 2     | 50          |
| [ 1, "jacket" ]   | 2020-01-02 00:00:00.000 | 3     | 52          |
| [ 1, "jacket" ]   | 2020-01-03 00:00:00.000 | 4     | 54          |
| [ 1, "jacket" ]   | 2020-01-04 00:00:00.000 | 5     | 54          |
| [ 1, "jacket" ]   | 2020-01-05 00:00:00.000 | 6     | 55          |
| [ 2, "umbrella" ] | 2020-01-01 00:00:00.000 | 2     | 50          |
| [ 2, "umbrella" ] | 2020-01-02 00:00:00.000 | 3     | 52          |
| [ 2, "umbrella" ] | 2020-01-03 00:00:00.000 | 4     | 54          |
| [ 2, "umbrella" ] | 2020-01-04 00:00:00.000 | 5     | 54          |
| [ 2, "umbrella" ] | 2020-01-05 00:00:00.000 | 6     | 55          |
+-------------------+-------------------------+-------+-------------+

以下语句使用上述数据集训练预测模型。请务必指定系列列名称,即 store_item

CREATE SNOWFLAKE.ML.FORECAST model4(
  INPUT_DATA => SYSTEM$REFERENCE('VIEW', 'v4'),
  SERIES_COLNAME => 'store_item',
  TIMESTAMP_COLNAME => 'date',
  TARGET_COLNAME => 'sales'
);
Copy

小技巧

您可以为 input_data 传递 查询引用,而不用创建中间视图。下面的语句使用与上一条语句相同的输入数据创建了一个模型:

CREATE SNOWFLAKE.ML.FORECAST model4(
  INPUT_DATA => SYSTEM$QUERY_REFERENCE('SELECT [store_id, item] AS store_item, date, sales, temperature FROM sales_data'),
  SERIES_COLNAME => 'store_item',
  TIMESTAMP_COLNAME => 'date',
  TARGET_COLNAME => 'sales'
);
Copy

和以前一样,在预测时,您需要输入外生变量的未来值,但这次是输入每个序列的未来值。准备外生变量的未来值:

CREATE OR REPLACE VIEW V4_FORECAST AS SELECT [store_id, item] AS store_item,
  date, temperature FROM future_features;
SELECT * FROM v4_forecast;
Copy

输出

+-------------------+-------------------------+-------------+
| STORE_ITEM        | DATE                    | TEMPERATURE |
+-------------------+-------------------------+-------------+
| [ 1, "jacket" ]   | 2020-01-13 00:00:00.000 | 52          |
| [ 1, "jacket" ]   | 2020-01-14 00:00:00.000 | 53          |
| [ 2, "umbrella" ] | 2020-01-13 00:00:00.000 | 52          |
| [ 2, "umbrella" ] | 2020-01-14 00:00:00.000 | 53          |
+-------------------+-------------------------+-------------+

现在,您可以根据前面的时间戳进行预测:

CALL model4!FORECAST(
  INPUT_DATA => SYSTEM$REFERENCE('VIEW', 'v4_forecast'),
  SERIES_COLNAME => 'store_item',
  TIMESTAMP_COLNAME =>'date'
);
Copy

输出

+-------------------+-------------------------+----------+-------------+-------------+
| SERIES            | TS                      | FORECAST | LOWER_BOUND | UPPER_BOUND |
+-------------------+-------------------------+----------+-------------+-------------+
| [ 1, "jacket" ]   | 2020-01-13 00:00:00.000 | 14       | 14          | 14          |
| [ 1, "jacket" ]   | 2020-01-14 00:00:00.000 | 15       | 15          | 15          |
| [ 2, "umbrella" ] | 2020-01-13 00:00:00.000 | 14       | 14          | 14          |
| [ 2, "umbrella" ] | 2020-01-14 00:00:00.000 | 15       | 15          | 15          |
+-------------------+-------------------------+----------+-------------+-------------+

可视化预测

要使预测可视化,请使用 Snowsight 图表功能。生成预测后,点击查询结果表上方的 Charts

您可以使用 UNION ALL 将原始数据和预测结果的 SELECTs 结合起来,将预测结果与原始数据集连接起来,这样就可以将两者可视化。例如:

CALL model4!FORECAST(FORECASTING_PERIODS => 3);
SELECT date AS ts, sales AS actual, NULL AS forecast, NULL AS lower_bound, NULL AS upper_bound
  FROM sales_data
UNION ALL
SELECT ts, NULL AS actual, forecast, lower_bound, upper_bound
  FROM TABLE(RESULT_SCAN(-1));
Copy

如有必要,重命名时间戳和外生变量列,使其在原始数据集和预测结果中相匹配。在使用 NULL 表示训练数据中的预测目标值,反之用于表示预测结果中的历史目标值。在前面的示例中,实际(历史)目标列重命名为 actual,预测目标列重命名为 forecast

以这种方式准备数据后,请在图表右侧的 Data 部分中按照以下步骤操作:

  1. 选择 ACTUAL 列,然后在 Aggregation 下,选择 None

  2. 选择 TS 列,然后在 Bucketing 下,选择 None

  3. 添加 FORECAST 列,选择 Use as Line,然后在 Aggregation 下选择 None

  4. 以相同的方式添加 LOWER_BOUNDUPPER_BOUND 列。

生成的图表应如下所示:

从时间序列预测创建图表的示例

了解特征的重要性

预测模型可以解释模型中使用的所有特征的相对重要性,包括您选择的任何外生变量、自动生成的时间特征(例如星期几或一年中的一周)以及目标变量的转换(例如滚动平均值和自动回归滞后)。这些信息有助于了解真正影响数据的要素。

<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 SNOWFLAKE.ML.FORECAST forecast_feature_importance_demo(
  INPUT_DATA => SYSTEM$REFERENCE('VIEW', 'v_random_data'),
  TIMESTAMP_COLNAME => 'ts',
  TARGET_COLNAME => 'y'
);

CALL forecast_feature_importance_demo!EXPLAIN_FEATURE_IMPORTANCE();
Copy

输出

+--------+------+--------------------------------------+-------+-------------------------+
| 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  |
+--------+------+--------------------------------------+-------+-------------------------+

了解评估指标

默认情况下,每个预测模型都经过交叉验证。除了基于所有提供的训练数据来训练模型之外,还会基于训练数据的子集来训练一个或多个模型,然后使用它们来“预测”保留的数据。之后会将预测的目标值与实际目标值进行比较。如果您不需要评估指标,或者不想在这些指标上花费计算资源,请在实例化模型时将 evaluate 设置为 FALSE。

限制

  • n_splits 参数必须至少设置为 2。

  • 小型数据集可能没有足够的数据来执行评估。训练行总数必须等于或大于 (n_splits * test_size) + gap。如果没有足够的数据来训练评估模型,则即使 evaluate 为 TRUE,也没有评估指标可用。

示例

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 SNOWFLAKE.ML.FORECAST model(
  INPUT_DATA => SYSTEM$REFERENCE('VIEW', 'v_random_data'),
  TIMESTAMP_COLNAME => 'ts',
  TARGET_COLNAME => 'y'
);

CALL model!SHOW_EVALUATION_METRICS();
Copy

输出

+--------+--------------------------+--------------+--------------------+------+
| SERIES | ERROR_METRIC             | METRIC_VALUE | STANDARD_DEVIATION | LOGS |
+--------+--------------------------+--------------+--------------------+------+
| NULL   | "MAE"                    |        7.107 |              1.998 | NULL |
| NULL   | "MAPE"                   |        0.475 |              0.237 | NULL |
| NULL   | "MDA"                    |        0.920 |              0.025 | NULL |
| NULL   | "MSE"                    |       86.020 |             66.798 | NULL |
| NULL   | "SMAPE"                  |        0.241 |              0.047 | NULL |
| NULL   | "COVERAGE_INTERVAL=0.95" |        0.981 |              0.025 | NULL |
| NULL   | "WINKLER_ALPHA=0.05"     |       56.697 |             45.199 | NULL |
+--------+--------------------------+--------------+--------------------+------+

检查训练日志

使用 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.FORECAST model(
  INPUT_DATA => SYSTEM$QUERY_REFERENCE('SELECT date, sales, series FROM t_error'),
  SERIES_COLNAME => 'series',
  TIMESTAMP_COLNAME => 'date',
  TARGET_COLNAME => 'sales',
  CONFIG_OBJECT => {'ON_ERROR': 'SKIP'}
);

CALL model!SHOW_TRAINING_LOGS();
Copy

输出

+--------+-------------------------------------------------------------------------------------------------+
| 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!forecast(...)').collect()
Copy
语言: 中文