時系列データの前処理

# はじめに
現在、時系列データの分析を行い、機械学習により未来予測をやっています。
そんな経験もあるおかげか、少し前に退職した先輩から時系列データの処理について質問をいただきました。
先「時系列データってどんな作業すればいいかわからん。」
僕「ラグ特徴量取ってればOKです！」
本当にごめんなさい。適当言ってました。というより、今まで自分が未熟すぎました。
今回は時系列データを分析していくうえで、まず初めにやるべきことについていくつかまとめました。

こちらの記事を参考にしました。
参照させていただきます。

https://qiita.com/tk-tatsuro/items/16ce74fc954b5a58df00

# 時系列データとは
まず時系列データでどのようなことができるのか。
トレンドの特定、周期性の検出、外れ値の識別、相関と因果関係の分析、未来予測など。
いろいろな分析ができます。
しかし、これらの分析を行う上で、データの前処理というのは非常に重要となります。
今回は未来予測をメインにどのような前処理をしていくかまとめていきます。

データを読み込んだ後は、インデックスに日付を指定しておくことで楽になります。
```python
import pandas as pd

df = pd.read_csv('file_path')
df.set_index('date',inplace=True)
```


# 傾向変動や季節変動、不規則変動の確認
解析の最初のステップは、データを視覚的に調べることです。
データにどのような傾向があるのか、季節的な変動、ランダムな変動などの特徴を確認することが重要です。
これによりデータの性質を把握することができます。
これらのトレンド、季節成分、残渣は`statsmodels`ライブラリの`seasonal_decompose`を使用して可視化することができます。

```python
import statsmodels.api as sm
import matplotlib.pyplot as plt

# 時系列データの季節成分を分解して可視化する関数
def plt_seasonal_decompose(df, col_name, period):
    # df: DataFrame - 時系列データを格納したデータフレーム
    # col_name: str - 分解対象の列名（時系列データ）
    # period: int - 季節成分の周期（季節性の周期）

    # statsmodelsのseasonal_decompose関数を使用して、指定した周期で季節成分を分解
    res = sm.tsa.seasonal_decompose(df[col_name], period=period)
    
    # 季節成分の分解結果を可視化するためのプロットを作成
    fig = res.plot()
    
    # プロットを表示
    plt.show()
```

さらに、トレンド推定の方法の1つとして移動平均を取ることも一般的だそうです。
```python
df[move_mean_column_name] = df['column_name'].rolling(100).mean().round(1)
```
rolling(100)：100期間のウィンドウサイズを持つ移動平均を計算
この値を変化させることで、移動平均の平均化期間が調整されます。
たとえばrolling(50)とすると、異なる期間での平均が計算されるため、結果として得られる移動平均データは、より短期的な傾向や変動を反映することになります。
このウィンドウサイズを変更することは、データの平滑化やトレンドの特定に影響を与える可能性があります。
ウィンドウサイズが小さい場合、移動平均はより短期的な変動に敏感に反応し、大きい場合はより長期的なトレンドに焦点を当てます。

# 周期性、時間的な相関の確認
データの周期性や時間的な相関を確認することで、データの性質を理解し、適切なモデルリング手法を選択するのに役立ちます。自己相関関数（ACF）や偏自己相関関数（PACF）を使用して、データの相関構造を調査することが一般的です。
このあたりはまだ試せてないので、後日別の記事でまとめようと思います。

# 定常性の確認
時系列データの分析では定常性は重要な指標となります。
- 予測性能の向上：未来の値を予測するためのモデルの作成や性能評価において、より信頼性の高い結果を提供可能。非定常なデータでは、トレンドや季節性が強調され、予測が困難になる。
- 統計モデルの適用：定常性のあるデータに対しては、多くの統計モデルが適用可能です。例えば、ARIMA（自己回帰和分移動平均モデル）などの一般的な時系列モデルは定常性を前提としています。
- 統計的仮定の保持：統計的仮定の1つに、観測データが独立同分布（i.i.d.）であるという仮定があります。定常性がない場合、この仮定が崩れ、統計的な信頼性が損なわれる可能性があります。
- モデルの解釈の容易性：定常性を持つデータのモデルは直感的に理解しやすく、パラメータの解釈が容易です。一方、非定常なデータでは、モデルが複雑になり、パラメータの解釈が難しくなることがあります。
- 信頼性の向上：統計的な信頼性が向上します。モデルの予測や推定が安定し、結果のバラつきが少なくなります。

といったように、定常性は非常に重要です。

そもそも定常性とはなにか。

- 定常性は、時系列データの基本的な特性の一つで、データの統計的性質が時間に依存しないことを示します。
- 強定常性（strict stationarity）と弱定常性（weak stationarity）の2つの概念があります。弱定常性は平均と分散が時間に依存しないことを意味し、強定常性はその他の統計的性質も含みます。
- 定常性があるデータは、統計モデルの前提条件を満たし、予測モデルを安定させるために重要です。非定常なデータでは、トレンドや季節性などが強調され、モデルが不安定になることがあります。

つまり、データの平均と分散が時間に依存しないことが大切であるということです。
ということで、データの平均と分散を見てみましょう。
```python
print(df[column_name].mean())
print(df[column_name].var())
```
これだけではよくわからないので、ADF検定を行い、定常性があるか確認します。
```python
from statsmodels.tsa.stattools import adfuller

def adf_test(series):
    adf_df = pd.DataFrame(
    [
        adfuller(series)[1]
    ],
    column=['P値']
    )
    adf_df['P値'] = adf_df['P値'].round(3).astype(str)
    print(adf_df)

adf_test(series=df[column_name])
```

ここでP値（有意水準）が0.05以下であれば、定常性があるといえます。
0.05より大きければ、非定常なデータであるため、特徴量を追加・生成したり、定常性を持つようにデータ変換する必要があります。

# データ変換を行い、再度ADF検定を行う
定常性がない場合は、データ変換を行う必要があります。
一般的なのは差分変換と対数変換です。
差分変換とは、1時点離れたデータとの差を取る手法です。
対数変換とは、変動が著しく大きな時系列データに対し、原系列の傾向を保持したまま、値を小さく変換する手法です。
データ変換を行った後は、平均と分散がどのように変化しているかも見ておくといいです。
このとき、並行して特徴量エンジニアリングをしてもいいかもしれませんね。
そして再度ADF検定を行い、定常性の確認を行います。

# 予測モデルを作成する
定常性が認められれば、適切な予測モデル（ARIMA、Exponential Smoothingなど）を構築し、未来の値を予測するためのモデルを訓練します。
ここでラグ特徴量を取って行けばいいんだと思います！

# まとめ
今回は時系列データの前処理についてまとめました。
参考にした記事と同じようなことばかり書いてしましましたが、定着させるためにアウトプットとして自分の表現で書かせていただきました。
(｡-人-｡) ｺﾞﾒﾝﾈ
他にもやれることはたくさんあると思います。
最低でもこれくらいはやっとかないとなってものをまとめましたので、ご参考になればと思います。
ここまで見ていただきありがとうございました！
それでは！！！