時系列予測 (Snowflake Cortex ML ベースの関数)

注釈

予測は、Snowflakeのインテリジェントなフルマネージド AI および ML サービスであるSnowflake Cortexの一部です。この機能は、Snowflake Cortex ML ベースの関数スイートの一部です。

予測は、過去の時系列データを用いて将来のデータを予測する機械学習アルゴリズムを採用しています。時系列予測は、過去の入力データに基づいて将来のデータの単変量予測を生成します一般的なユースケースとしては、季節性やその他の要因に基づく売上予測が挙げられます。

過去のデータには次が含まれている必要があります。

  • タイムスタンプ列。一定の頻度(例えば、1時間毎、5分毎など)を指定する必要があります。

  • 各タイムスタンプで興味のある数量を表すターゲット値の列。

過去のデータには、ターゲットに影響を与えた可能性のある追加列(外生変数)も含まれます。これらの列は数値データでも文字データでもかまいません。

過去のデータは、将来のタイムスタンプでターゲット値の予測を生成する、機械学習モデルをトレーニングするために使用します。モデルはスキーマレベルのオブジェクトであり、トレーニングされた後、複数の予測に使用することができます。(モデルは、過去のデータと同じ範囲の予測を作成するために使用することはできません)。

予測は単一系列または複数系列のデータで機能します。複数系列データは、イベントの複数の個別のスレッドを表します。たとえば、複数の店舗の販売データがある場合は、各店舗の売上を店舗識別子に基づいて1つのモデルで個別に予測することができます。

時系列データの予測を作成するには、Snowflake組み込みクラス FORECAST を使用し、次のステップに従います。

  1. 予測モデルオブジェクトを作成 し、トレーニングデータへの参照を渡します。このオブジェクトは、提供されたトレーニングデータにモデルを適合(トレーニング)させます。モデルはスキーマレベルのオブジェクトです。

  2. この予測モデルオブジェクトを使用して、将来のタイムスタンプに対するターゲットの予測を作成するために forecast method を呼び出し、タイムステップの数、または外生変数を使用している場合は将来の値の外生データのいずれかを渡します。

重要

法律上の注意点。 このSnowflake Cortex ML ベースの機能は、機械学習技術によって実現されています。機械学習技術と提供される結果は、不正確、不適切であったり、偏っていたりする可能性があります。自動パイプラインに組み込まれたものも含め、機械学習の出力に基づく決定には、モデルが生成したコンテンツが正確であることを保証するために、人間によるモニタリングとレビュープロセスが必要です。Snowflake Cortexの ML ベースの関数クエリは、他の SQL クエリと同様に扱われ、 メタデータ と見なされる可能性があります。

メタデータ。 Snowflake Cortex ML ベース関数を使用する場合、Snowflakeのログは メタデータフィールド に述べられている内容に加えて、 ML 関数によって返される一般的なエラーメッセージを記録します。これらのエラーログは、発生した問題のトラブルシューティングや、お客様により良いサービスを提供するための機能改善に役立ちます。

予測アルゴリズムについて

予測アルゴリズムは、 勾配ブースティングマシン (GBM)を使用しています。 ARIMA モデルのように、非定常トレンドを持つデータをモデリングするために差分変換を使用し、モデル変数として過去のターゲットデータの自己回帰ラグを使用します。

さらに、このアルゴリズムは、過去のターゲットデータの移動平均を使用してトレンドの予測を支援し、タイムスタンプデータから周期的なカレンダー変数(曜日や週番号など)を自動的に生成します。

過去のターゲット値とタイムスタンプのデータだけでモデルを適合させることも、ターゲット値に影響を与えた可能性のある外生データ(変数)を含めることもできます。外生変数は、数値またはカテゴリ別の値であり、 NULL (外生変数の NULLs を含む行はドロップされません)の場合もあります。

このアルゴリズムは、カテゴリ別変数でトレーニングする際にone-hotエンコーディングに依存しないため、ディメンション数の多い(カーディナリティの高い)カテゴリデータを使用することができます。

モデルに外生変数が組み込まれている場合は、予測を生成する際に完全な予測範囲のタイムスタンプごとにそれらの変数の値を提供する必要があります。適切な外生変数には、気象情報(気温、降雨量)、企業固有の情報(これまでの、および計画されている企業の休日、広告キャンペーン、イベントスケジュール)、またはターゲット変数の予測に役立つと思われるその他の外部要因などがあります。

アルゴリズムは、予測に加えて予測区間も生成します。予測区間とは、データのある割合が該当する可能性のある上限値と下限値内の推定値の範囲を表します。たとえば、0.95という値は、データの95%が区間内に出現する可能性が高いことを意味します。予測区間を指定することも、デフォルトの0.95を使用することもできます。予測区間の下限と上限は、予測出力の一部として返されます。

重要

Snowflakeは予測アルゴリズムを改良することがあり、そのような改良は定期的なSnowflakeのリリースプロセスを通じてロールアウトされます。以前のバージョンの特徴量に戻すことはできませんが、以前のバージョンで作成したモデルは、引き続きそのバージョンを予測に使用します。

現在の制限

現在のリリースには次の制限があります。

  • 予測アルゴリズムの選択や調整はできません。

  • 主な予測アルゴリズムの最小行数は、時系列ごとに12です。観測データが2と11の間の時系列では、予測はすべての予測値が最後に観測されたターゲット値に等しい「ナイーブ」な予測を生成します。

  • 予測関数は、トレンド、季節性、または季節振幅を上書きするパラメーターを提供しません。パラメーターはデータから推測されます。

  • データの最小許容粒度は1秒です。(タイムスタンプの間隔は1秒以内でなければなりません。)

  • 季節要因の最小粒度は1分です。(関数はより小さな時間差で周期的なパターンを検出することはできません。)

  • データのタイムスタンプは、一定の時間間隔を表す必要があります。入力データが不規則な場合は、モデルのトレーニング時にタイムスタンプ列の DATE_TRUNC または TIME_SLICE を試行します。

  • 自己回帰的な特徴量の「シーズンの長さ」は、入力頻度に関連付けられています(1時間ごとのデータでは24、1日ごとのデータでは7など)。

  • 予測モデルは、一度トレーニングすると不変です。新しいデータで既存のモデルを更新することはできず、まったく新しいモデルをトレーニングする必要があります。モデルはバージョニングをサポートしていません。Snowflakeでは、新しいデータを受け取る頻度に応じて、毎日、毎週、毎月など、定期的にモデルを再トレーニングし、変化するパターンやトレンドにモデルを適応させることを推奨しています。

  • モデルをクローンしたり、ロールやアカウント間でモデルを共有したりすることはできません。スキーマやデータベースをクローンする場合、モデルオブジェクトはスキップされます。

  • FORECAST クラスのインスタンスを 複製 することはできません。

予測の準備

予測を使用する前に、以下が必要です。

また、 SNOWFLAKE.ML を含めるように 検索パスを変更 する場合もあります。

仮想ウェアハウスの選択

Snowflake 仮想ウェアハウス は、この特徴量のための機械学習モデルをトレーニングし、使用するためのコンピューティングリソースを提供します。このセクションでは、プロセスの中で最も時間とメモリを消費する部分であるトレーニングステップに焦点を当て、この目的に最適なウェアハウスのタイプとサイズを選択するための一般的なガイダンスを提供します。

単一系列データのトレーニング

単一系列データで学習したモデルの場合、トレーニングデータのサイズに基づいてウェアハウスタイプを選択します。標準ウェアハウスは、 Snowparkのメモリ制限 が低く、行数が少ないトレーニングジョブや外生変数に適しています。

トレーニングデータに外生変数が含まれていない場合、データセットが500万行以下であれば、標準ウェアハウスでトレーニングできます。トレーニングデータが5以上の外生変数を使用している場合、最大行数は少なくなります。それ以外の場合は、大規模なトレーニングジョブに対して Snowparkに最適化されたウェアハウス を使用することをSnowflakeは提案します。

一般的に、単一系列データの場合、ウェアハウスサイズが大きくなっても、トレーニング時間が短縮されたり、メモリ制限が高くなったりすることはありません。大まかな経験則として、トレーニング時間は時系列の行数に比例します。たとえば、 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用に最適化

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 admin_db TO ROLE analyst;
GRANT USAGE ON 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 analyist_db.analyist_schema;
Copy

スキーマ上のロールの予測モデル作成権限を取り消すには、 REVOKE <権限> を使用します。

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

例に対するデータの設定

以下の例では、2つのテーブルを作成します。これらのテーブルのビューは、このトピックで後述する に含まれています。

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.FORECAST は制限された権限で実行されるため、デフォルトではご使用のデータにアクセスできません。そのため、テーブルとビューを 参照 として渡す必要があります。参照は、呼び出し元の権限も一緒に渡します。テーブルやビューへの参照ではなく、 クエリ参照 を提供することもできます。

予測を生成するには、モデルの <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(...) で予測を作成できます。同じモデルを使用して、複数のデータセットから予測を作成することができます。

次の例では、モデルを作成し、そこから予測を作成する方法を示します。すべてのパラメーターの詳細については、 <name>!FORECAST をご参照ください。

ちなみに

モデルのトレーニングに使用されたデータセットとは異なる列名を持つデータセットでモデルを使用するには、列名をモデルが期待する名前に変更する(AS を使用)ビューやクエリを作成します。そのビューまたはクエリ を FORECASTメソッドの入力として使用します。

モデルの作成時および使用時に使用するパラメーターについては、 FORECAST をご参照ください。

以下の例では、さまざまなユースケースで時系列予測を使用しています。

単一系列の予測

この例では、タイムスタンプ列とターゲット値列の2つの列を持つ単一時系列(つまり、すべての行が単一時系列の一部)を使用します。まず、 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 として利用できるようになりました。次の3つのタイムスタンプを予測するには、

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

出力

モデルは、トレーニングデータからタイムスタンプの間隔を推測していることに注意してください。

+-------------------------+-----------+--------------+--------------+
| TS                      | FORECAST  | LOWER_BOUND  | UPPER_BOUND  |
+-------------------------+-----------+--------------+--------------+
| 2020-01-13 00:00:00.000 | 14        | 14           | 14           |
| 2020-01-14 00:00:00.000 | 15        | 15           | 15           |
| 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 クエリの結果にある最初の5行です。

+-------------------------+--------+-------------+----------+----------+
| 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)に将来値を提供する必要があります。これにより、「もし気温が平年より低かったら?」のような「what-if」という質問ができるようになります。ここで、将来のタイムスタンプのために、このデータを含む 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 ビューから得られます。

+-------------------------+-----------+--------------+--------------+
| TS                      | FORECAST  | LOWER_BOUND  | UPPER_BOUND  |
+-------------------------+-----------+--------------+--------------+
| 2020-01-13 00:00:00.000 | 14        | 14           | 14           |
| 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

出力

結果として得られるデータセットにおける各系列の最初の5行は、

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

トレーニング後、すべての系列を同時に2ステップ進める(つまり、系列ごとに2ステップ進む)ことができます。

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の傘の販売について、次の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 メソッドで1つの系列を指定すると、1つの系列の予測のみが生成されるため、関心のある系列のみを含むように複数系列の予測結果をフィルタリングするよりも効率的です。

外生変数を含む複数系列の予測

外生変数と並行して複数の時系列をトレーニングして予測するには、基本的に前の2つの例を組み合わせて、次の方法でデータを準備し、系列の列(ここでは store_item)と少なくとも1つの外生列(ここでは temperature)の両方を組み込みます。

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

出力

結果として得られるデータセットにおける各系列の最初の5行は、次のようになります。

+-------------------+-------------------------+-------+-------------+
| 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 列を選択し、 AggregationNone を選択します。

  2. TS 列を選択し、 BucketingNone を選択します。

  3. FORECAST 列を追加し、 Use as Line を選択し、 AggregationNone を選択します。

  4. LOWER_BOUNDUPPER_BOUND 列も同様に追加します。

結果として得られるチャートは次のようになります。

Example of creating a chart from a time series forecast

特徴量の重要性について

予測モデルは、選択した外生変数や自動生成時間特徴量(曜日や週番号など)、ターゲット変数の変換(移動平均や自己回帰ラグなど)など、モデルで使用されるすべての特徴量の相対的な重要性を説明することができます。この情報は、データに実際に影響を与えている要因を理解するのに役立ちます。

<name>!EXPLAIN_FEATURE_IMPORTANCE メソッドは、モデルのツリーが各特徴量を使用して決定した回数をカウントします。それから、これらの特徴量の重要度スコアは、合計が1になるように0から1の間の値に正規化されます。結果として得られるスコアは、トレーニング済みモデルの特徴量の近似ランキングを表します。

スコアが近い特徴量は同じような重要性を持ちます。極端に単純な系列(たとえば、対象列の値が一定の場合)では、すべての特徴量の重要度スコアが0になる可能性があります。

互いによく似た複数の特徴量を使用すると、それらの特徴量の重要度スコアが低下する可能性があります。たとえば、ある特徴量が 販売個数 であり、別の特徴量が 在庫個数 である場合、その値は相関している可能性があります。なぜなら、在庫個数よりも多く販売することはできず、在庫個数は販売個数よりも多くならないように在庫を管理しようとするからです。2つの特徴量がまったく同じである場合、モデルは決定を下す際にそれらを交換可能なものとして扱い、その結果、同じ特徴量のうちの1つだけが含まれていた場合には、特徴量の重要度スコアは本来のスコアの半分になる可能性があります。

特徴量の重要度は、 ラグ特徴量 も報告します。トレーニング中、モデルはトレーニングデータの頻度(毎時、毎日、毎週)を推測します。特徴量 lagx (例: lag24)は、ターゲット変数 x 単位時間前の値です。たとえば、データが1時間ごとと推測される場合、 lag24 は24時間前のターゲット変数を表します。

ターゲット変数の他のすべての変換(移動平均など)は、結果テーブルの aggregated_endogenous_features として要約されます。

制限事項

  • 特徴量の重要度を計算する手法は選択できません。

  • 特徴量の重要度スコアは、どの特徴量がモデルの精度にとって重要かを直感的に理解するのに役立ちますが、実際の値は推測として考慮される必要があります。

モデルに対する特徴量の相対的な重要性を理解するには、モデルをトレーニングしてから、 <name>!EXPLAIN_FEATURE_IMPORTANCE を呼び出します。この例では、まず2つの外生変数を持つランダムデータを作成します。1つはランダムであるためモデルにとって重要性が低くなると考えられ、もう1つはターゲットのコピーであるためモデルにとって重要性が高くなると考えられます。

以下のステートメントを実行すると、データが生成され、モデルがトレーニングされ、特徴量の重要度が取得されます。

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

出力

+------+--------------------------------------+-------+-------------------------+
| RANK | FEATURE_NAME                         | SCORE | FEATURE_TYPE            |
+------+--------------------------------------+-------+-------------------------+
|    1 | aggregated_endogenous_trend_features |  0.36 | derived_from_endogenous |
|    2 | exog_a                               |  0.22 | user_provided           |
|    3 | epoch_time                           |  0.15 | derived_from_timestamp  |
|    4 | minute                               |  0.13 | derived_from_timestamp  |
|    5 | lag60                                |  0.07 | derived_from_endogenous |
|    6 | lag120                               |  0.06 | derived_from_endogenous |
|    7 | hour                                 |  0.01 | derived_from_timestamp  |
+------+--------------------------------------+-------+-------------------------+

評価指標の理解

デフォルトでは、すべての予測モデルは交差検証されます。提供されたすべての訓練データでモデルをトレーニングすることに加えて、1つ以上のモデルがトレーニングデータのサブセットでトレーニングされ、その後、保留されたデータを「予測」するために使用されます。予測されたターゲット値は、実際のターゲット値と比較されます。評価メトリクスが不要な場合や、評価メトリクスに計算リソースを使いたくない場合は、モデルのインスタンス化時に 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

出力

+--------------------------+--------------+--------------------+------+
| ERROR_METRIC             | METRIC_VALUE | STANDARD_DEVIATION | LOGS |
+--------------------------+--------------+--------------------+------+
| "MAE"                    |        7.107 |              1.998 | NULL |
| "MAPE"                   |        0.475 |              0.237 | NULL |
| "MDA"                    |        0.920 |              0.025 | NULL |
| "MSE"                    |       86.020 |             66.798 | NULL |
| "SMAPE"                  |        0.241 |              0.047 | NULL |
| "COVERAGE_INTERVAL=0.95" |        0.981 |              0.025 | 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