(Python編) 時系列データをサクッとSTLでトレンド・季節性に分解

(Python編) 時系列データをサクッとSTLでトレンド・季節性に分解

幸か不幸か、ビジネス系のデータの多くは時系列データです。売上データもホームーページのアクセスログもセンサーデータも時系列データです。

時系列データを手にしたとき、どのようなデータなのか見てみたい、ということは多々あります。

多くの場合、折れ線グラフを描き傾向を掴む、ということをやります。

折れ線グラフを眺めると、トレンド(上昇傾向や下降傾向)や季節性などが見て取れるケースがあります。

そこで、サクッとトレンドや季節性などを掴む手法が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)が非常に小さいことご分かります。要は、元データはトレンドと季節性でほぼ構成されているということです。

(R編) 時系列データをサクッとSTLでトレンド・季節性に分解