季節調整済みARIMAモデルで電力使用状況を推定してみる
北海道電力の電力使用状況を季節調整済みARIMAモデル(Seasonal ARIMA)で推定してみました。そのメモです。
このサイトを参考にしました。ほぼそのままやりました。
■Seasonal ARIMA with Python
http://www.seanabu.com/2016/03/22/time-series-seasonal-ARIMA-model-in-python/
このブログでも紹介されていますが、statsmodelsのdevelopment versionが必要です。
https://github.com/statsmodels/statsmodels
これをインストールするにはvisual c++のなんかのバージョンが必要で色々と面倒でした。あと、pipでインストールすると失敗するのでeasy_installでうまくいく場合もありました。
%pylab
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import datetime
from dateutil.relativedelta import relativedelta
import seaborn as sns #グラフが見やすくなる
import statsmodels.api as sm
from statsmodels.tsa.stattools import acf
from statsmodels.tsa.stattools import pacf
from statsmodels.tsa.seasonal import seasonal_decompose
data = pd.read_csv("http://denkiyoho.hepco.co.jp/data/2016_juyo_hokkaidou.csv", skiprows=3,names=['Date','Time','power'])
data.index = pd.to_datetime(data['Date'])
df = data.groupby(data.index).mean()
df['power'] = df.power.apply(lambda x: int(x)*10000)
df.power.plot(figsize=(12,6), title= 'Power', fontsize=14)
ここからトレンド、季節変動、、残差(ランダム成分)にわけます。
plt.close() df = pd.DataFrame(df['power'].values.astype(int), pd.DatetimeIndex(start='2016-01-01', periods=len(df['power']), freq='D')) df.columns= ['power'] decomposition = seasonal_decompose(df.values, freq=7) fig = plt.figure() fig = decomposition.plot() fig.set_size_inches(8, 8)
ここから定常性を確認します。参考にした記事に良いものがありましたので使わせてもらいます。
plt.close()
from statsmodels.tsa.stattools import adfuller
def test_stationarity(timeseries):
#Determing rolling statistics
rolmean = pd.rolling_mean(timeseries, window=7)
rolstd = pd.rolling_std(timeseries, window=7)
#Plot rolling statistics:
fig = plt.figure(figsize=(8, 6))
orig = plt.plot(timeseries, color='blue',label='Original')
mean = plt.plot(rolmean, color='red', label='Rolling Mean')
std = plt.plot(rolstd, color='black', label = 'Rolling Std')
plt.legend(loc='best')
plt.title('Rolling Mean & Standard Deviation')
plt.show()
#Perform Dickey-Fuller test:
print ("Results of Dickey-Fuller Test:")
dftest = adfuller(timeseries, autolag='AIC')
dfoutput = pd.Series(dftest[0:4], index=['Test Statistic','p-value','#Lags Used','Number of Observations Used'])
for key,value in dftest[4].items():
dfoutput['Critical Value (%s)'%key] = value
print (dfoutput)
test_stationarity(df.power)
###Results of Dickey-Fuller Test:###
Test Statistic -1.832150
p-value 0.364621
#Lags Used 14.000000
Number of Observations Used 351.000000
Critical Value (1%) -3.449119
Critical Value (5%) -2.869810
Critical Value (10%) -2.571176
dtype: float64
データは定常性ではないことがわかります。
次に1次の差分をとった場合です。
plt.close() df['first_difference'] = df.power - df.power.shift(1) test_stationarity(df.first_difference.dropna(inplace=False)) ###Results of Dickey-Fuller Test:### Test Statistic -5.660888e+00 p-value 9.385886e-07 #Lags Used 1.300000e+01 Number of Observations Used 3.510000e+02 Critical Value (1%) -3.449119e+00 Critical Value (5%) -2.869810e+00 Critical Value (10%) -2.571176e+00 dtype: float64
次は季節性の差分をとります。
plt.close() df['seasonal_difference'] = df.power - df.power.shift(7) test_stationarity(df.seasonal_difference.dropna(inplace=False)) ###Results of Dickey-Fuller Test:### Test Statistic -3.452940 p-value 0.009281 #Lags Used 14.000000 Number of Observations Used 344.000000 Critical Value (1%) -3.449503 Critical Value (5%) -2.869979 Critical Value (10%) -2.571266 dtype: float64
一次の差分と、季節性を取り除きます。
plt.close() df['seasonal_first_difference'] = df.first_difference - df.first_difference.shift(7) test_stationarity(df.seasonal_first_difference.dropna(inplace=False)) ###Results of Dickey-Fuller Test:### Test Statistic -9.147004e+00 p-value 2.750689e-15 #Lags Used 1.300000e+01 Number of Observations Used 3.440000e+02 Critical Value (1%) -3.449503e+00 Critical Value (5%) -2.869979e+00 Critical Value (10%) -2.571266e+00 dtype: float64
ACFとPACFからパラメータを選びます。
plt.close() fig = plt.figure(figsize=(8,6)) ax1 = fig.add_subplot(211) fig = sm.graphics.tsa.plot_acf(df.seasonal_first_difference.iloc[8:], lags=40, ax=ax1) ax2 = fig.add_subplot(212) fig = sm.graphics.tsa.plot_pacf(df.seasonal_first_difference.iloc[8:], lags=40, ax=ax2)
こちらを参考にモデルのパラメータを選べばいいそうです。
■ARIMA models for time series forecasting
http://people.duke.edu/~rnau/arimrule.htm
もっと簡単にパラメータを選ぶ方法があればいいと思いますが、ないんですかね?
seasonal_order=(0,1,1,7)とseasonal_order=(1,1,1,7)でモデルを作成してみました。
plt.close()
mod = sm.tsa.statespace.SARIMAX(df.power, trend='n', order=(0,1,0), seasonal_order=(0,1,1,7))
results = mod.fit()
print (results.summary())
Statespace Model Results
=========================================================================================
Dep. Variable: power No. Observations: 366
Model: SARIMAX(0, 1, 0)x(0, 1, 1, 7) Log Likelihood -4772.423
Date: Thu, 09 Mar 2017 AIC 9548.846
Time: 21:04:58 BIC 9556.607
Sample: 01-01-2016 HQIC 9551.932
- 12-31-2016
Covariance Type: opg
==============================================================================
coef std err z P>|z| [0.025 0.975]
------------------------------------------------------------------------------
ma.S.L7 -0.4498 0.012 -36.021 0.000 -0.474 -0.425
sigma2 1.674e+10 2.7e-13 6.21e+22 0.000 1.67e+10 1.67e+10
===================================================================================
Ljung-Box (Q): 50.61 Jarque-Bera (JB): 1021.36
Prob(Q): 0.12 Prob(JB): 0.00
Heteroskedasticity (H): 0.52 Skew: -1.32
Prob(H) (two-sided): 0.00 Kurtosis: 10.84
===================================================================================
Warnings:
[1] Covariance matrix calculated using the outer product of gradients (complex-step).
[2] Covariance matrix is singular or near-singular, with condition number 1.36e+37. Standard errors may be unstable.
mod = sm.tsa.statespace.SARIMAX(df.power, trend='n', order=(0,1,0), seasonal_order=(1,1,1,7))
results = mod.fit()
print (results.summary())
Statespace Model Results
=========================================================================================
Dep. Variable: power No. Observations: 366
Model: SARIMAX(0, 1, 0)x(1, 1, 1, 7) Log Likelihood -4745.075
Date: Thu, 09 Mar 2017 AIC 9496.150
Time: 21:06:44 BIC 9507.792
Sample: 01-01-2016 HQIC 9500.780
- 12-31-2016
Covariance Type: opg
==============================================================================
coef std err z P>|z| [0.025 0.975]
------------------------------------------------------------------------------
ar.S.L7 0.4606 0.020 22.704 0.000 0.421 0.500
ma.S.L7 -0.9589 0.030 -32.239 0.000 -1.017 -0.901
sigma2 1.614e+10 2.89e-13 5.57e+22 0.000 1.61e+10 1.61e+10
===================================================================================
Ljung-Box (Q): 88.63 Jarque-Bera (JB): 7.99
Prob(Q): 0.00 Prob(JB): 0.02
Heteroskedasticity (H): 0.63 Skew: -0.26
Prob(H) (two-sided): 0.01 Kurtosis: 3.52
===================================================================================
Warnings:
[1] Covariance matrix calculated using the outer product of gradients (complex-step).
[2] Covariance matrix is singular or near-singular, with condition number inf. Standard errors may be unstable.
seasonal_order=(1,1,1,7)のほうがAICとBICの値が小さくなっていましたのでseasonal_order=(1,1,1,7)でグラフにしてみます。
fig, ax = plt.subplots()
ax.set(title='HOKKAIDO POWER', xlabel='Date', ylabel='Power')
ax.plot(df.power.ix['2016-01-01':], 'g',label="power",color="darkgrey")
ax.plot(results.predict(start = 364, end= 380, dynamic= True),'g',label="forcast",color="green")
legend = ax.legend(loc='lower right')
legend.get_frame().set_facecolor('w')
ほほーという感じですね。もう少しいろいろなデータで検証してみたいと思います。
※参考
■Statsmodels Examples
http://www.statsmodels.org/devel/examples/index.html
■Rで季節変動のある時系列データを扱ってみる
http://tjo.hatenablog.com/entry/2013/10/30/190552
関連する投稿:
- 2017-02-11:Python3でビットコインの回帰線を描いてみる
- 2017-03-14:季節調整済みARIMAモデルで電力使用状況を推定してみる part2 予測表示
- 2017-01-25:軍需企業の株価
- 2017-03-17:SARIMAXモデルでPVを予測してみる
- 2017-02-24:電力データから季節変動の分解








“季節調整済みARIMAモデルで電力使用状況を推定してみる” への2件の返信