TIMESNETモデルを用いた株式相場予想

# はじめに[^1]

本紙はTIMESNETの論文解説を行うものです。

TIMESNET: TEMPORAL 2D-VARIATION MODELING FOR GENERAL TIME SERIES ANALYSIS

![Screenshot 2024-04-01 at 10.44.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731268/1f7c5ae1-9503-e109-194e-5268a0df69d9.png)

従来の時系列分析は、1つの周期性しか考慮できないため、気象データのような複数の周期を持つデータには対応できません。そこで、時間系列を2D空間に拡張することで、期間内変動と期間間変動という2種類の時間変動を同時に分析できます。TimesNetは、TimesBlockと呼ばれる新しいモジュールを用いて、多周期性の時間系列を分析します。TimesBlockは、1D時系列を2Dテンソルのセットに変換することで、期間内変動と期間間変動を分離します。

### 期間内変動と期間間変動とは

期間内変動：同じ周期内の短期的な時間的パターン
期間間変動：連続した異なる周期の長期的な傾向

# TimesBlock

![Screenshot 2024-04-01 at 10.57.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731268/47f9970a-8d78-f809-3ed3-374b476867bc.png)

## FFT for Periods

![Screenshot 2024-04-01 at 11.08.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731268/96120a08-3fd7-17de-cfb2-f37965ca9154.png)

高速フーリエ変換（FFT）を用いて周期性を発見することで、元の1D時系列データを2Dテンソルに変換します。論文上では、上位３つに分ける

## Reshape

高速フーリエ変換（FFT）の戻り値に従い、D時系列を2DテンソルのセットにReshapeします。
paddingをした後で、Reshapeを行います。

## Inception Block

ここが、実際に学習を行う部位です。

![Screenshot 2024-04-01 at 12.39.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731268/cafbe1b0-468d-b8e0-d45e-50954d060740.png)

画像引用元: [TimesNet解説まとめ -時系列予測モデル-](https://zenn.dev/yuto_mo/articles/c2197b9897fefd)



## Reshape BackとAdaptive Aggregation

最後に2Dテンソルを一次元の時系列データに戻します。
元の長さに切り捨てます。

Adaptive Aggregation処理に関して、以下の数式にあるように、元の時系列データに対して、softmax処理を行い、それを重みとして、Reshape Backした時系列データに掛け合わせます。


```math
\begin{align}
\mathbf{\hat{A}}_{f_1}^{l-1}, \cdots, \mathbf{\hat{A}}_{f_k}^{l-1} &= Softmax(\mathbf{A}_{f_1}^{l-1}, \cdots, \mathbf{A}_{f_k}^{l-1}) \\
X_{1D}^l &= \sum_{i=1}^{k}\mathbf{\hat{A}}_{f_i}^{l-1}\times \hat{X}^{l,i}_{1D}
\end{align}
```

# 結果

>TimesNetは平均精度73.6%で最高のパフォーマンスを達成し、以前の最先端の古典的な方法Rocket（72.5%）とディープモデルFlowformer（73.0%）を上回っています。

LSTMはもう古いモデルになりました。

![Screenshot 2024-04-04 at 11.32.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731268/04330546-491a-09c5-94a1-ec130c1e87db.png)


# 実装

まずはライブラリーをimport

```python:import
!pip install neuralforecast > /dev/null 2>&1

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from typing import Tuple

from sklearn import preprocessing
from sklearn.preprocessing import StandardScaler

from google.colab import drive
import time

from neuralforecast.core import NeuralForecast
from neuralforecast.models import NHITS, NBEATS, TimesNet
from neuralforecast.utils import AirPassengersDF
```
preprocess_dataは、CSVデータを読み込み、時系列分析のための前処理を行い、DataFrameを返します。

```python:preprocess_data
def preprocess_data(data_path):
    """
    CSVデータを読み込み、時系列分析のための前処理を行い、DataFrameを返す。
    Args:
        data_path (str): データを含むCSVファイルへのパス。
    Returns:
        pd.DataFrame: 時系列分析の準備ができた前処理済みの DataFrame。
    """
    df = pd.read_csv(data_path)
    try:
        df['ds'] = pd.to_datetime(df['Date'])
    except pd.errors.OutOfBoundsDatetime:
        print("Error: Date format might be invalid. Please check your data.")
        return None
    df['y'] = preprocessing.scale(df['SP500'])
    df['unique_id'] = 1.0
    df.drop(columns=['Date', 'SP500'], inplace=True)
    df = df.reindex(columns=['unique_id', 'ds', 'y'])
    return df
```

訓練データとテストデータを作ります。

```python
df_train = preprocess_data(nov_train)
df_test = preprocess_data(nov_test)
df_train.info()
```

出力されたデータの形式は以下のようになります。
この形式でないと、neuralforecastのモデルの予想はできない。

```console
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 628 entries, 0 to 627
Data columns (total 3 columns):
 #   Column     Non-Null Count  Dtype         
---  ------     --------------  -----         
 0   unique_id  628 non-null    float64       
 1   ds         628 non-null    datetime64[ns]
 2   y          628 non-null    float64       
dtypes: datetime64[ns](1), float64(2)
memory usage: 14.8 KB
```

modelの予想の処理です。

```python:add_predict_column
def add_predict_column(df, model, input_size):
    """
    df_testにpredict列を追加し返す関数
    Args:
        df_test: テストデータのDataFrame
        model: 予測モデル
        input_size: モデルのinput_size
    Returns:
        predict列を追加したDataFrame
    """
    df_predict = pd.DataFrame()
    for i in range(len(df) - input_size):
        arr = df[i:input_size+i]
        predict = model.predict(df=arr, verbose=True)
        df_predict = df_predict.append(predict)
    return df_predict
```

訓練と予想のフェーズ

```python
input_size=100
network = [TimesNet(h=1, input_size=input_size, max_steps=100)]
model = NeuralForecast(models=network, freq='D')
model.fit(df=df_train)
df_predict = add_predict_column(df_test, model, input_size)
```

最後にプロットをします。

```python
import matplotlib.pyplot as plt

plt.figure(figsize=(15, 5))
plt.plot(df_test.ds, df_test.y, label="Actual")
plt.plot(df_predict.ds, df_predict.TimesNet, label="Predictions")
plt.title("Actual vs. Predicted")
plt.legend()
plt.show()
```

# 結果

かなり精度が高いです。

https://github.com/sugiyama404/forecast_sp500/blob/main/TIMESNET.ipynb

![Unknown.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/731268/75fd8db5-c6af-6bff-e73b-31b275b6f988.png)


[^1]: 'TIMESNET: Temporal 2D-Variation Modeling for General Time Series Analysis'. Haixu Wu, Tengge Hu, Yong Liu, Hang Zhou, Jianmin Wang, Mingsheng Long In International Conference on Learning Representations (ICLR) (pp. 1-23).