Pythonで時系列分析の練習(6)トレンド、季節性、残差に分解

Pythonで時系列分析の練習(6)トレンド、季節性、残差に分解

Pythonで時系列分析する手法をモモノキ&ナノネと一緒に学習していきます。

モモノキ&ナノネと一緒にPythonで時系列分析を覚えよう(6)




時系列分析の実践練習(トレンド、季節性、残差)

前回の続き、飛行機乗客数のデータを使って時系列分析の練習をするよ。ナノネ、前回データを読み込んでグラフを1枚描いたとこまで一式実行してみて。

In [1]:
# 第5回コードの抜粋
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
plt.style.use('ggplot') # グラフのデザイン変更(お好みで利用)
plt.xkcd() # グラフのデザイン変更(お好みで利用)
import statsmodels.api as sm # version 0.8.0以上

# CSVファイル読み込み(事前にダウンロードしたCSVファイルを利用)
df = pd.read_csv('AirPassengers.csv')

# Pandas.Seriesにデータを格納(データに乗客数、インデックスは日付)
passengers = pd.Series(df['#Passengers'], dtype='float') # ①
passengers.index = pd.to_datetime(df['Month']) # ②

# Pasdasでグラフをプロット(Matplotlibの機能を利用している)
passengers.plot()
Out[1]:
<matplotlib.axes._subplots.AxesSubplot at 0xab82fcec>

前回コードから必要な箇所だけコピペして...準備できた。

OK。乗客数の時系列データをグラフで見ると、ギザギザを繰り返しながら年々増えていたよね。

ギザギザはどれも似たような形をしている。でも、年々フレが大きくなっているみたい。

グラフから推察すると、右方上がりの傾向は飛行機が便利なって年々利用者が増加している。ギザギザの山は大型連休などがある月に飛行機を利用する人が多そう。みたいな感じでデータの変化を読み取れそうだね。

このデータで右方上がりに増えいるような傾向を『トレンド』というんだよ。全体的に増えている、減っているなどの変化の傾向を示すものだよ。

山みたいなギザギザの繰り返しも名前があるの?

周期的に繰り返す変動は『季節性』と呼ばれたりするよ。英語だと『Seasonality』だね。ちなみに四季とは直接関係なくても周期的な変動は季節性と表現するみたい。

TrendとSeasonalityだね。覚えておく。

それと、トレンドと季節性を除いたその他変動成分を『残差』と呼んだりするよ。英語で表現すると『Residual』だよ。残差の成分は誤差やノイズとも表現されるみたい。

Trend、Seasonality、それとResidualも覚えておく。

今回の飛行機乗客数のデータを、トレンド、季節性、残差にそれぞれ分解してみよう。

どうやってTrend、Seasonality、Residualに分解するの?

StatsModelsに分解する機能があるから、簡単にできるよ。今回StatsModelsはsmという名前でインポートしているから、sm.tsa.seasonal_decompose(時系列データ)とすればOKだよ。

seasonal_decompose、でこぽーず??、直訳だと季節的に分解するかな。

In [2]:
sm.tsa.seasonal_decompose(passengers)
Out[2]:
<statsmodels.tsa.seasonal.DecomposeResult at 0xb5a8912c>

実行したけど、文字が出ただけ。stastsmodels...DecomposeResult?

ゴメン、実行すると解析結果の詰め合わせが返ってくるので、適当な変数で受け取ってみて。それから、DecomposeResultの解析データを使ってグラフを描いてみよう。

In [3]:
res = sm.tsa.seasonal_decompose(passengers)

resという変数で受け取った。グラフはどう描けばいいの。

オリジナル、トレンド、季節性、残差をまとめて一辺にグラフ化できるけど、今回は練習なのでひとつずつ描画する方法を試してみよう。

DecomposeResult解析結果(変数res)の中にトレンド、季節性、残差に分割されたデータが入っているよ。それぞれの分割済みデータはDecomposeResult変数のあとに.trend、.seasonal、.residとすれば取り出せるよ。

オリジナル、トレンド、季節性、残差のグラフ4個を縦に並べて描いてみよう。あと、Matplotlibで複数グラフを描く方法はいくつかあるので、以前書いた下のリンク記事も参考にしてみてね。

Matplotlibの使い方は教えてくれないの?!
...しかたないから、キホン的なグラフの描き方は一人で練習してきた。

In [4]:
# res = sm.tsa.seasonal_decompose(passengers) # 解析結果は取得済み

original = passengers # オリジナルデータ
trend = res.trend # トレンドデータ
seasonal = res.seasonal # 季節性データ
residual = res.resid # 残差データ

plt.figure(figsize=(8, 8)) # グラフ描画枠作成、サイズ指定

# オリジナルデータのプロット
plt.subplot(411) # グラフ4行1列の1番目の位置(一番上)
plt.plot(original)
plt.ylabel('Original')

# trend データのプロット
plt.subplot(412) # グラフ4行1列の2番目の位置
plt.plot(trend)
plt.ylabel('Trend')

# seasonalデータ のプロット
plt.subplot(413) # グラフ4行1列の3番目の位置
plt.plot(seasonal)
plt.ylabel('Seasonality')

# residual データのプロット
plt.subplot(414) # グラフ4行1列の4番目の位置(一番下)
plt.plot(residual)
plt.ylabel('Residuals')

plt.tight_layout() # グラフの間隔を自動調整

それぞれデータを指定してplot()。4枚のグラをうまく描けた。

一番上はオリジナル、二つ目はトレンド、三つ目は季節性、一番下が残差。seasonal_decomposeでトレンド、季節性、残差にうまく分割できたね。

トレンドと季節性と残差を足し合わせるとオジリナルと一致するの?

分割しただけだから、足せば一致するはずだけど。試しに確認してみてみて。

In [5]:
# res = sm.tsa.seasonal_decompose(passengers) # 解析結果は取得済み

original = passengers # オリジナルデータ
trend = res.trend # トレンドデータ
seasonal = res.seasonal # 季節性データ
residual = res.resid # 残差データ
sum_three_data = trend + seasonal + residual # トレンド + 季節性 + 残差

plt.figure(figsize=(8, 4)) # グラフ描画枠作成、サイズ指定
plt.plot(original, label='original')
plt.plot(sum_three_data, label='trend +season +resid', linestyle='--')
plt.legend(loc='best') # 凡例表示
Out[5]:
<matplotlib.legend.Legend at 0xaa0d08ec>

最初と最後の方のデータは無くなってるけど、3つ足しわせるとオリジナルと一致する。

OKだね。最初と最後の方のデータがないのは、たぶん周期性とか求める関係かな?

乗客数は何月が多いんだろう?このグラフだとわかりにくいなぁ。
モモノキ、確認できる?

グルーピングとかで、月別の平均値を求めれば確認できそうだけど。グーグル先生に聞いてみて。

In [6]:
passengers.groupby(passengers.index.month).mean()
Out[6]:
1     241.750000
2     235.000000
3     270.166667
4     267.083333
5     271.833333
6     311.666667
7     351.333333
8     351.083333
9     302.416667
10    266.583333
11    232.833333
12    261.833333
Name: #Passengers, dtype: float64

グーグル先生に聞いてみたら、Pandasのgroupbyが使えそう。インデックスの月でグルーピングして月別の平均値を出してみた。

ナノネ、グラフにしてみて。簡単なPandasプロットならplot(kind='bar')で棒グラフが作れるよ。

In [7]:
passengers_month_mean = passengers.groupby(passengers.index.month).mean()
passengers_month_mean.plot(kind='bar')
Out[7]:
<matplotlib.axes._subplots.AxesSubplot at 0xa9f9e7ac>

平均だと、7〜8月の乗客数が多いみたい。夏休みの影響かな?海外のバカンスは長いようだし。

このデータだけで要因までは特定できないけど、夏場に乗客数が多いのは確かだね。

今回はここまで。次回は自己相関について学習しよう。

自己相関??、ラジャー。





スポンサーリンク

0 件のコメント :

コメントを投稿