幸か不幸か、ビジネス系のデータの多くは時系列データです。売上データもホームーページのアクセスログもセンサーデータも時系列データです。
時系列データを手にしたとき、どのようなデータなのか見てみたい、ということは多々あります。
多くの場合、折れ線グラフを描き傾向を掴む、ということをやります。
折れ線グラフを眺めると、トレンド(上昇傾向や下降傾向)や季節性などが見て取れるケースがあります。
そこで、サクッとトレンドや季節性などを掴む手法がSTL分解(Seasonal Decomposition Of Time Series By Loess)です。
STL分解(Seasonal Decomposition Of Time Series By Loess)を実施することで、元データをトレンド、季節性、残差に分解することができます。
元データ = トレンド + 季節性 + 残差
STL分解(Seasonal Decomposition Of Time Series By Loess)は、LOESS平滑化(locally estimated scatterplot smoothing)というノンパラメトリック回帰モデルを利用します。
理論的なお話しはさておき、今回は「(Python編) 時系列データをサクッとSTLでトレンド・季節性に分解」というお話しをします。
超簡単です。
必要なライブラリー
統計解析用の以下のライブラリーを使います。
statsmodelsさえあれば、色々な統計解析ができるので、STL分解(Seasonal Decomposition Of Time Series By Loess)されない方も、インストールしておいて損はありません。
statsmodels User Guide
https://www.statsmodels.org/stable/user-guide.html
インストールされていない方は、以下のコードを参考にインストールして頂ければと思います。
conda install -c conda-forge statsmodels
データセットの読み込みや処理などに「pandas」を、グラフの描写には「matplotlib」を使います。どちらもPyhtonでよく使うライブラリーですので、インストールされていない方はインストールしておくことをお勧めします。
この2つのライブラリーがインストールされているものとして話しを進めます。
では最初に、必要なライブラリーの読み込みます。
# ライブラリーの読み込み import pandas as pd #基本ライブラリー from statsmodels.tsa.seasonal import STL #STL分解 import matplotlib.pyplot as plt #グラフ描写
ついでに、グラフのスタイルを次のように「ggplot」に設定します。この処理は必須ではありません。別のスタイルでも問題ございません。
#グラフのスタイル plt.style.use('ggplot')
サンプルデータ
Box and Jenkins (1976) の有名な「Airline Passengers」(飛行機乗客数)のデータセット(csvファイル)を使って作業を行います。
「Airline Passengers」(飛行機乗客数)のデータセット(csvファイル)は、pandasを使い読み込みます。
CSVファイルは、https://www.salesanalytics.co.jp/591h上にあるものを使います
# データセットの読み込み url='https://www.salesanalytics.co.jp/591h' #データセットのあるURL table=pd.read_csv(url, #読み込むデータのURL index_col='Month', #変数「Month」をインデックスに設定 parse_dates=True) #インデックスを日付型に設定
データの中を見てみます。
以下、コードです。
table.head()
以下、実行結果です。
月別の乗客数のデータであることが分かります。
どのようなデータなのか、その情報を確認してみます。
以下、コードです。
table.info()
実行結果です。
データフレーム型(DataFrame)で、変数は「Passengers」のみで、データ数(行)は144あり、データの型は整数型(int64)であることが分かります。
変数「Month」はインデックスとして利用されています。
グラフで確認
読み込んだ「Airline Passengers」(飛行機乗客数)のデータセットをグラフで眺めてみたいと思います。
先ず、グラフサイズを設定します。この処理は必須ではありません。
# グラフサイズ設定 plt.rcParams['figure.figsize'] = [12, 9]
では、折れ線グラフを描写してみます。
以下、コードです。
# プロット table.plot() plt.title('Passengers') #グラフタイトル plt.ylabel('Monthly Number of Airline Passengers') #タテ軸のラベル plt.xlabel('Month') #ヨコ軸のラベル plt.show()
以下、実行結果です。
トレンドとして上昇傾向であり、季節性もありそうなことが分かります。
STL分解(Seasonal Decomposition Of Time Series By Loess)
STL分解(Seasonal Decomposition Of Time Series By Loess)は非常に簡単です。実質2行のコードで事足ります。
STL分解(Seasonal Decomposition Of Time Series By Loess)を実施し、元データをトレンド、季節性、残差に分解していきたいと思います。。
元データ = トレンド + 季節性 + 残差
以下、コードです。
# STL分解 stl=STL(table['Passengers'], period=12, robust=True) stl_series = stl.fit()
どのように分解されたのか、グラフで確認したいと思います。
以下、コードです。
# STL分解結果のグラフ化 stl_series.plot() plt.show()
以下、実行結果です。
STL分解(Seasonal Decomposition Of Time Series By Loess)した結果を抽出したい、という要望もあることでしょう。実際に取り出してみたいと思います。
以下、コードです。
# STL分解結果のデータ stl_o = stl_series.observed #観測データ(STL分解前の元のデータ)=トレンド+季節性+残差 stl_t = stl_series.trend #トレンド(trend) stl_s = stl_series.seasonal #季節性(seasonal) stl_r = stl_series.resid #残差(resid)
取り出したデータ(トレンド、季節性、残差)の中身を見てみましょう。
では、トレンド(trend)を見てみます。
以下、コードです。
stl_t
以下、実行結果です。
グラフ化してみます。
以下、コードです。
stl_t.plot() plt.title('Trend') #グラフタイトル plt.ylabel('Monthly Number of Airline Passengers') #タテ軸のラベル plt.xlabel('Month') #ヨコ軸のラベル plt.show()
以下、実行結果です。
次に、STL分解(Seasonal Decomposition Of Time Series By Loess)して得られたトレンド、季節性、残差の3つを同時にグラフで描写してみたいと思います。
以下、コードです。
stl_t.plot() #トレンド(trend)のグラフ描写 stl_s.plot() #季節性(season)のグラフ描写 stl_r.plot() #残差(resid)のグラフ描写 plt.title('Passengers') #グラフタイトル plt.ylabel('Monthly Number of Airline Passengers') #タテ軸のラベル plt.xlabel('Month') #ヨコ軸のラベル plt.legend() #凡例表示 plt.show()
以下、実行結果です。
トレンドと季節性に比べ、残差(resid)が非常に小さいことご分かります。要は、元データはトレンドと季節性でほぼ構成されているということです。